public override WebSocket CreateWebSocket(Stream stream, WebSocketListenerOptions options, IPEndPoint localEndpoint, IPEndPoint remoteEndpoint, WebSocketHttpRequest httpRequest, WebSocketHttpResponse httpResponse, List<IWebSocketMessageExtensionContext> negotiatedExtensions)
 {
     var webSocket = new WebSocketRfc6455(stream, options, localEndpoint, remoteEndpoint, httpRequest, httpResponse, negotiatedExtensions);
     if (OnPingReceived != null)
         webSocket.OnPingReceived = OnPingReceived;
     return webSocket;
 }
        internal WebSocketConnectionRfc6455(Stream clientStream, WebSocketListenerOptions options)
        {
            Guard.ParameterCannotBeNull(clientStream, "clientStream");
            Guard.ParameterCannotBeNull(options, "options");

            _writeSemaphore = new SemaphoreSlim(1);
            _options = options;
            
            _clientStream = clientStream;

            if (options.BufferManager != null)
                _buffer = options.BufferManager.TakeBuffer(14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4 + 2);
            else
                _buffer = new Byte[14 + 125 + 125 + 8 + 10 + _options.SendBufferSize  + 4 + 2];

            _headerBuffer = new ArraySegment<Byte>(_buffer, 0, 14);
            _controlBuffer = new ArraySegment<Byte>(_buffer, 14, 125);
            _pongBuffer = new ArraySegment<Byte>(_buffer, 14 + 125, 125);
            _pingBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125, 8);
            SendBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125 + 8 + 10, _options.SendBufferSize);
            _keyBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize, 4);
            _closeBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4, 2);

            switch (options.PingMode)
            {
                case PingModes.BandwidthSaving:
                    _ping = new BandwidthSavingPing(this, _options.PingTimeout, _pingBuffer);
                    break;
                case PingModes.LatencyControl:
                default:
                    _ping = new LatencyControlPing(this, _options.PingTimeout, _pingBuffer);
                    break;
            }
        }
        public HttpNegotiationQueue(WebSocketFactoryCollection standards, WebSocketConnectionExtensionCollection extensions, WebSocketListenerOptions options)
        {
            Guard.ParameterCannotBeNull(standards, "standards");
            Guard.ParameterCannotBeNull(extensions, "extensions");
            Guard.ParameterCannotBeNull(options, "options");

            _options = options;
            _extensions = extensions;
            _cancel = new CancellationTokenSource();
            _semaphore = new SemaphoreSlim(options.ParallelNegotiations);
            
            _sockets = new BufferBlock<Socket>(new DataflowBlockOptions()
            {
                BoundedCapacity = options.NegotiationQueueCapacity,
                CancellationToken = _cancel.Token
            });

            _negotiations = new BufferBlock<WebSocketNegotiationResult>(new DataflowBlockOptions()
            {
                BoundedCapacity = options.NegotiationQueueCapacity,
                CancellationToken = _cancel.Token,
            });

            _cancel.Token.Register(_sockets.Complete);
            _cancel.Token.Register(_negotiations.Complete);

            _handShaker = new WebSocketHandshaker(standards, _options);

            Task.Run((Func<Task>)WorkAsync);
        }
        public WebSocketRfc6455(Stream clientStream, WebSocketListenerOptions options, IPEndPoint local, IPEndPoint remote, WebSocketHttpRequest httpRequest, IReadOnlyList<IWebSocketMessageExtensionContext> extensions)
        {
            if (clientStream == null)
                throw new ArgumentNullException("clientStream");

            if (options == null)
                throw new ArgumentNullException("options");

            if (local == null)
                throw new ArgumentNullException("local");

            if (remote == null)
                throw new ArgumentNullException("remote");

            if (extensions == null)
                throw new ArgumentNullException("extensions");

            if (httpRequest == null)
                throw new ArgumentNullException("httpRequest");

            _remoteEndpoint = remote;
            _localEndpoint = local;
            _httpRequest = httpRequest;

            Connection = new WebSocketConnectionRfc6455(clientStream, options);
            _extensions = extensions;
        }
        internal WebSocketConnectionRfc6455(Stream clientStream, WebSocketListenerOptions options)
        {
            if (clientStream == null)
                throw new ArgumentNullException("clientStream");

            if (options == null)
                throw new ArgumentNullException("options");

            _writeSemaphore = new SemaphoreSlim(1);
            _options = options;
            
            _clientStream = clientStream;

            if (options.BufferManager != null)
                _buffer = options.BufferManager.TakeBuffer(14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4 + 2);
            else
                _buffer = new Byte[14 + 125 + 125 + 8 + 10 + _options.SendBufferSize  + 4 + 2];

            _headerBuffer = new ArraySegment<Byte>(_buffer, 0, 14);
            _controlBuffer = new ArraySegment<Byte>(_buffer, 14, 125);
            _pongBuffer = new ArraySegment<Byte>(_buffer, 14 + 125, 125);
            _pingBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125, 8);
            SendBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125 + 8 + 10, _options.SendBufferSize);
            _keyBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize, 4);
            _closeBuffer = new ArraySegment<Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4, 2);

            _pingTimeout = _options.PingTimeout;
            _pingInterval = TimeSpan.FromMilliseconds(Math.Min(500, _options.PingTimeout.TotalMilliseconds / 2));
        }
        public WebSocketRfc6455(Stream clientStream, WebSocketListenerOptions options, IPEndPoint local, IPEndPoint remote, WebSocketHttpRequest httpRequest, WebSocketHttpResponse httpResponse, IReadOnlyList<IWebSocketMessageExtensionContext> extensions)
            :base(httpRequest, httpResponse)
        {
            Guard.ParameterCannotBeNull(clientStream, "clientStream");
            Guard.ParameterCannotBeNull(options, "options");
            Guard.ParameterCannotBeNull(local, "local");
            Guard.ParameterCannotBeNull(remote, "remote");
            Guard.ParameterCannotBeNull(extensions, "extensions");
            Guard.ParameterCannotBeNull(httpRequest, "httpRequest");

            _remoteEndpoint = remote;
            _localEndpoint = local;

            Connection = new WebSocketConnectionRfc6455(clientStream, options);
            _extensions = extensions;
        }
Пример #7
0
        internal WebSocketConnectionRfc6455(Stream clientStream, WebSocketListenerOptions options)
        {
            Guard.ParameterCannotBeNull(clientStream, "clientStream");
            Guard.ParameterCannotBeNull(options, "options");

            _writeSemaphore = new SemaphoreSlim(1);
            _options        = options;

            _clientStream = clientStream;

            if (options.BufferManager != null)
            {
                _buffer = options.BufferManager.TakeBuffer(14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4 + 2);
            }
            else
            {
                _buffer = new Byte[14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4 + 2];
            }

            _headerBuffer  = new ArraySegment <Byte>(_buffer, 0, 14);
            _controlBuffer = new ArraySegment <Byte>(_buffer, 14, 125);
            _pongBuffer    = new ArraySegment <Byte>(_buffer, 14 + 125, 125);
            _pingBuffer    = new ArraySegment <Byte>(_buffer, 14 + 125 + 125, 8);
            SendBuffer     = new ArraySegment <Byte>(_buffer, 14 + 125 + 125 + 8 + 10, _options.SendBufferSize);
            _keyBuffer     = new ArraySegment <Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize, 4);
            _closeBuffer   = new ArraySegment <Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4, 2);

            switch (options.PingMode)
            {
            case PingModes.BandwidthSaving:
                _ping = new BandwidthSavingPing(this, _options.PingTimeout, _pingBuffer);
                break;

            case PingModes.LatencyControl:
            default:
                _ping = new LatencyControlPing(this, _options.PingTimeout, _pingBuffer);
                break;
            }
        }
        public WebSocketRfc6455(Stream clientStream, WebSocketListenerOptions options, IPEndPoint local, IPEndPoint remote, WebSocketHttpRequest httpRequest, WebSocketHttpResponse httpResponse, IReadOnlyList <IWebSocketMessageExtensionContext> extensions)
            : base(httpRequest, httpResponse)
        {
            if (clientStream == null)
            {
                throw new ArgumentNullException("clientStream");
            }

            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            if (local == null)
            {
                throw new ArgumentNullException("local");
            }

            if (remote == null)
            {
                throw new ArgumentNullException("remote");
            }

            if (extensions == null)
            {
                throw new ArgumentNullException("extensions");
            }

            if (httpRequest == null)
            {
                throw new ArgumentNullException("httpRequest");
            }

            _remoteEndpoint = remote;
            _localEndpoint  = local;

            Connection  = new WebSocketConnectionRfc6455(clientStream, options);
            _extensions = extensions;
        }
Пример #9
0
        public HttpNegotiationQueue(WebSocketFactoryCollection standards, WebSocketConnectionExtensionCollection extensions, WebSocketListenerOptions options)
        {
            if (standards == null)
            {
                throw new ArgumentNullException(nameof(standards));
            }
            if (extensions == null)
            {
                throw new ArgumentNullException(nameof(extensions));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            this.log = options.Logger;

            _options    = options;
            _extensions = extensions;
            _cancel     = new CancellationTokenSource();
            _semaphore  = new SemaphoreSlim(options.ParallelNegotiations);

            _connections  = new AsyncQueue <NetworkConnection>(options.NegotiationQueueCapacity);
            _negotiations = new AsyncQueue <WebSocketNegotiationResult>();
            _negotiations.ParallelTakeErrorMessage = $"Parallel call to '{nameof(WebSocketListener.AcceptWebSocketAsync)}' is not allowed.";
            _negotiations.ClosedErrorMessage       = $"{nameof(WebSocketListener)} is closed and will not accept new connections.";

            //_cancel.Token.Register(() => this._connections.Close(new OperationCanceledException()));

            _handShaker = new WebSocketHandshaker(standards, _options);

            if (options.PingMode != PingMode.Manual)
            {
                this.pingQueue = new PingQueue(options.PingInterval);
            }

            WorkAsync().LogFault(this.log);
        }
Пример #10
0
        public WebSocketEventListener(WebSocketOptions options)
        {
            options.ValidateOptions();
            _options = options.Clone();

            var opts = new WebSocketListenerOptions
            {
                // Must disable negotiation timeout for AOT iOS support.
                NegotiationTimeout           = TimeSpan.Zero,
                PingTimeout                  = TimeSpan.Zero,
                PingMode                     = PingMode.Manual,
                CertificateValidationHandler = _options.CertificateValidationHandler
            };

            opts.Standards.RegisterRfc6455();
            opts.Transports.ConfigureTcp(tcpTransport =>
            {
                tcpTransport.NoDelay = true;
                // Dual mode needed for IPv6 support. Does not work with Mono :(
                tcpTransport.DualMode = _options.DualMode;
            });
            _client = new WebSocketClient(opts);
        }
Пример #11
0
        public void WebSocketHandshaker_CanDoHttpFallback()
        {
            var options = new WebSocketListenerOptions();

            options.HttpFallback = _fallback.Object;
            WebSocketHandshaker handshaker = new WebSocketHandshaker(_factories, options);

            using (var ms = new MemoryStream())
            {
                using (var sw = new StreamWriter(ms, Encoding.ASCII, 1024, true))
                {
                    sw.WriteLine(@"GET /chat HTTP/1.1");
                    sw.WriteLine(@"Host: server.example.com");
                    sw.WriteLine(@"Cookie: key=W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5;");
                    sw.WriteLine(@"Origin: http://example.com");
                }

                var position = ms.Position;
                ms.Seek(0, SeekOrigin.Begin);

                var result = handshaker.HandshakeAsync(ms).Result;
                Assert.IsNotNull(result);
                Assert.IsFalse(result.IsWebSocketRequest);
                Assert.IsFalse(result.IsValidWebSocketRequest);
                Assert.IsTrue(result.IsValidHttpRequest);
                Assert.IsFalse(result.IsVersionSupported);
                Assert.AreEqual(new Uri("http://example.com"), result.Request.Headers.Origin);
                Assert.AreEqual("server.example.com", result.Request.Headers[HttpRequestHeader.Host]);
                Assert.AreEqual(@"/chat", result.Request.RequestUri.ToString());
                Assert.AreEqual(1, result.Request.Cookies.Count);
                var cookie = result.Request.Cookies["key"];
                Assert.AreEqual("key", cookie.Name);
                Assert.AreEqual(@"W9g/8FLW8RAFqSCWBvB9Ag==#5962c0ace89f4f780aa2a53febf2aae5", cookie.Value);
                Assert.IsNotNull(result.Request.LocalEndpoint);
                Assert.IsNotNull(result.Request.RemoteEndpoint);
            }
        }
        internal WebSocketConnectionRfc6455(Stream clientStream, WebSocketListenerOptions options)
        {
            if (clientStream == null)
            {
                throw new ArgumentNullException("clientStream");
            }

            if (options == null)
            {
                throw new ArgumentNullException("options");
            }

            _writeSemaphore = new SemaphoreSlim(1);
            _options        = options;

            _clientStream = clientStream;

            if (options.BufferManager != null)
            {
                _buffer = options.BufferManager.TakeBuffer(14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4 + 2);
            }
            else
            {
                _buffer = new Byte[14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4 + 2];
            }

            _headerBuffer  = new ArraySegment <Byte>(_buffer, 0, 14);
            _controlBuffer = new ArraySegment <Byte>(_buffer, 14, 125);
            _pongBuffer    = new ArraySegment <Byte>(_buffer, 14 + 125, 125);
            _pingBuffer    = new ArraySegment <Byte>(_buffer, 14 + 125 + 125, 8);
            SendBuffer     = new ArraySegment <Byte>(_buffer, 14 + 125 + 125 + 8 + 10, _options.SendBufferSize);
            _keyBuffer     = new ArraySegment <Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize, 4);
            _closeBuffer   = new ArraySegment <Byte>(_buffer, 14 + 125 + 125 + 8 + 10 + _options.SendBufferSize + 4, 2);

            _pingTimeout  = _options.PingTimeout;
            _pingInterval = TimeSpan.FromMilliseconds(Math.Min(500, _options.PingTimeout.TotalMilliseconds / 2));
        }
        /// <summary>
        /// Creates the connection to the B******g Server and performs the protocol handshake.
        /// </summary>
        /// <returns>Nothing (Task used for async/await)</returns>
        public async Task ConnectAsync(CancellationToken aToken = default(CancellationToken))
        {
            if (_ws != null)
            {
                throw new ButtplugHandshakeException(_logger, "Websocket connector is already connected.");
            }

            const int bufferSize     = 1024 * 8;         // 8KiB
            const int bufferPoolSize = 100 * bufferSize; // 800KiB pool
            var       options        = new WebSocketListenerOptions
            {
                // set send buffer size (optional but recommended)
                SendBufferSize = bufferSize,

                // set buffer manager for buffers re-use (optional but recommended)
                BufferManager = BufferManager.CreateBufferManager(bufferPoolSize, bufferSize),
            };

            // register RFC6455 protocol implementation (required)
            options.Standards.RegisterRfc6455();
            _wsClient = new WebSocketClient(options);

            try
            {
                _ws = await _wsClient.ConnectAsync(_uri, aToken).ConfigureAwait(false);
            }
            catch (Exception e)
            {
                throw new ButtplugClientConnectorException(_logger, "Websocket Connection Exception! See Inner Exception", e);
            }

            _readTask = new Task(async() => { await RunClientLoop(aToken).ConfigureAwait(false); },
                                 aToken,
                                 TaskCreationOptions.LongRunning);
            _readTask.Start();
        }
Пример #14
0
        public MKNClient()
        {
            cancellation = new CancellationTokenSource();

            var bufferSize     = 1024 * 8;         // 8KiB
            var bufferPoolSize = 100 * bufferSize; // 800KiB pool

            var options = new WebSocketListenerOptions
            {
                SubProtocols             = new[] { "text" },
                PingTimeout              = TimeSpan.FromSeconds(5),
                NegotiationTimeout       = TimeSpan.FromSeconds(5),
                PingMode                 = PingMode.Manual,
                ParallelNegotiations     = 16,
                NegotiationQueueCapacity = 256,
                BufferManager            = BufferManager.CreateBufferManager(bufferPoolSize, bufferSize)
            };

            options.Standards.RegisterRfc6455(factory =>
            {
                factory.MessageExtensions.RegisterDeflateCompression();
            });
            // configure tcp transport
            options.Transports.ConfigureTcp(tcp =>
            {
                tcp.BacklogSize       = 100; // max pending connections waiting to be accepted
                tcp.ReceiveBufferSize = bufferSize;
                tcp.SendBufferSize    = bufferSize;
            });

            // adding the WSS extension
            //var certificate = new X509Certificate2(File.ReadAllBytes("<PATH-TO-CERTIFICATE>"), "<PASSWORD>");
            // options.ConnectionExtensions.RegisterSecureConnection(certificate);

            client = new WebSocketClient(options);
        }
 internal abstract Task <NetworkConnection> ConnectAsync(Uri address, WebSocketListenerOptions options, CancellationToken cancellation);
        public HttpNegotiationQueue(WebSocketFactoryCollection standards, WebSocketConnectionExtensionCollection extensions, WebSocketListenerOptions options)
        {
            _options    = options;
            _extensions = extensions;
            _cancel     = new CancellationTokenSource();
            _semaphore  = new SemaphoreSlim(options.ParallelNegotiations);

            _sockets = new BufferBlock <Socket>(new DataflowBlockOptions()
            {
                BoundedCapacity   = options.NegotiationQueueCapacity,
                CancellationToken = _cancel.Token
            });
            _negotiations = new BufferBlock <WebSocketNegotiationResult>(new DataflowBlockOptions()
            {
                BoundedCapacity   = options.NegotiationQueueCapacity,
                CancellationToken = _cancel.Token,
            });

            _cancel.Token.Register(_sockets.Complete);
            _cancel.Token.Register(_negotiations.Complete);

            _handShaker = new WebSocketHandshaker(standards, _options);

            Task.Run((Func <Task>)WorkAsync);
        }
Пример #17
0
 public override WebSocket CreateWebSocket(Stream stream, WebSocketListenerOptions options, IPEndPoint localEndpoint, IPEndPoint remoteEndpoint, WebSocketHttpRequest httpRequest, WebSocketHttpResponse httpResponse, List <IWebSocketMessageExtensionContext> negotiatedExtensions)
 {
     return(new WebSocketRfc6455(stream, options, localEndpoint, remoteEndpoint, httpRequest, httpResponse, negotiatedExtensions));
 }
 internal abstract Task <Listener> ListenAsync(Uri address, WebSocketListenerOptions options);
Пример #19
0
        //[InlineData("tcp://127.0.0.1:10102/", 30, 1000)]
        //[InlineData("tcp://127.0.0.1:10103/", 40, 10000)]
        public async Task EchoServerMassClientsAsync(string address, int timeoutSeconds, int maxClients)
        {
            var messages     = new string[] { new string('a', 126), new string('a', 127), new string('a', 128), new string('a', ushort.MaxValue - 1), new string('a', ushort.MaxValue), new string('a', ushort.MaxValue + 2) };
            var startTime    = DateTime.UtcNow;
            var cancellation = new CancellationTokenSource(TimeSpan.FromSeconds(timeoutSeconds)).Token;
            var options      = new WebSocketListenerOptions
            {
                NegotiationQueueCapacity = maxClients,
                PingTimeout = TimeSpan.FromSeconds(30),
                Logger      = new TestLogger(this.logger)
                {
                    IsDebugEnabled = System.Diagnostics.Debugger.IsAttached
                }
            };

            options.Standards.RegisterRfc6455();
            options.Transports.ConfigureTcp(tcp =>
            {
                tcp.IsAsync        = true;
                tcp.NoDelay        = false;
                tcp.BacklogSize    = maxClients;
                tcp.SendTimeout    = TimeSpan.FromSeconds(15);
                tcp.ReceiveTimeout = TimeSpan.FromSeconds(15);
            });
            options.Transports.Add(new NamedPipeTransport());
            var listenEndPoints = new[] { new Uri(address) };
            var server          = new EchoServer(listenEndPoints, options);

            this.logger.Debug("[TEST] Starting echo server.");
            await server.StartAsync().ConfigureAwait(false);

            var messageSender = new MessageSender(listenEndPoints[0], options);

            this.logger.Debug("[TEST] Connecting clients.");
            await messageSender.ConnectAsync(maxClients, cancellation).ConfigureAwait(false);

            this.logger.Debug($"[TEST] {messageSender.ConnectedClients} Client connected.");
            this.logger.Debug($"[TEST] Sending {maxClients * messages.Length} messages.");
            var sendTask = messageSender.SendMessagesAsync(messages, cancellation);

            while (sendTask.IsCompleted == false && cancellation.IsCancellationRequested == false)
            {
                await Task.Delay(1000);

                this.logger.Debug($"[TEST] T:{timeoutSeconds - (DateTime.UtcNow - startTime).TotalSeconds:F0} " +
                                  $"Server: r={server.ReceivedMessages}, s={server.SentMessages}, e={server.Errors}. " +
                                  $"Clients: r={messageSender.MessagesReceived}, s={messageSender.MessagesSent}, e={messageSender.Errors}.");
            }

            var errorMessages = new SortedDictionary <string, int>(StringComparer.OrdinalIgnoreCase);

            server.PushErrorMessagesTo(errorMessages);
            messageSender.PushErrorMessagesTo(errorMessages);

            if (errorMessages.Count > 0)
            {
                this.logger.Debug("Errors:");
                foreach (var kv in errorMessages)
                {
                    this.logger.Debug($"[TEST] [x{kv.Value}] {kv.Key}");
                }
            }


            if (cancellation.IsCancellationRequested)
            {
                throw new TimeoutException();
            }

            await sendTask.ConfigureAwait(false);

            this.logger.Debug("[TEST] Stopping echo server.");
            await server.StopAsync().ConfigureAwait(false);

            this.logger.Debug("[TEST] Echo server stopped.");
            this.logger.Debug("[TEST] Disconnecting clients.");
            await messageSender.CloseAsync().ConfigureAwait(false);

            this.logger.Debug("[TEST] Disposing server.");
            server.Dispose();

            this.logger.Debug("[TEST] Waiting for send/receive completion.");
        }
Пример #20
0
        public WebSocketConnectionRfc6455([NotNull] NetworkConnection networkConnection, bool maskData, [NotNull] WebSocketListenerOptions options)
        {
            if (networkConnection == null)
            {
                throw new ArgumentNullException(nameof(networkConnection));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            const int HEADER_SEGMENT_SIZE      = 16;
            const int PONG_SEGMENT_SIZE        = 128;
            const int PING_HEADER_SEGMENT_SIZE = 16;
            const int PING_SEGMENT_SIZE        = 128;
            const int SEND_HEADER_SEGMENT_SIZE = 16;
            const int CLOSE_SEGMENT_SIZE       = 2;

            this.log = options.Logger;

            this.writeSemaphore = new SemaphoreSlim(1);
            this.options        = options;

            this.networkConnection = networkConnection;
            this.maskData          = maskData;

            var bufferSize = HEADER_SEGMENT_SIZE +
                             PING_HEADER_SEGMENT_SIZE + PONG_SEGMENT_SIZE +
                             PING_HEADER_SEGMENT_SIZE + PING_SEGMENT_SIZE +
                             PING_HEADER_SEGMENT_SIZE + PONG_SEGMENT_SIZE +
                             PING_HEADER_SEGMENT_SIZE + PING_SEGMENT_SIZE +
                             CLOSE_SEGMENT_SIZE;

            var smallBuffer = this.options.BufferManager.TakeBuffer(bufferSize);

            this.headerBuffer  = new ArraySegment <byte>(smallBuffer, 0, HEADER_SEGMENT_SIZE);
            this.outPongBuffer = this.headerBuffer.NextSegment(PING_HEADER_SEGMENT_SIZE).NextSegment(PONG_SEGMENT_SIZE);
            this.outPingBuffer = this.outPongBuffer.NextSegment(PING_HEADER_SEGMENT_SIZE).NextSegment(PING_SEGMENT_SIZE);
            this.inPongBuffer  = this.outPingBuffer.NextSegment(PING_HEADER_SEGMENT_SIZE).NextSegment(PONG_SEGMENT_SIZE);
            this.inPingBuffer  = this.inPongBuffer.NextSegment(PING_HEADER_SEGMENT_SIZE).NextSegment(PING_SEGMENT_SIZE);
            this.closeBuffer   = this.inPingBuffer.NextSegment(CLOSE_SEGMENT_SIZE);

            var sendBuffer = this.options.BufferManager.TakeBuffer(this.options.SendBufferSize);

            this.SendBuffer = new ArraySegment <byte>(sendBuffer, SEND_HEADER_SEGMENT_SIZE, sendBuffer.Length - SEND_HEADER_SEGMENT_SIZE);

            switch (options.PingMode)
            {
            case PingMode.BandwidthSaving:
                this.pingHandler = new BandwidthSavingPing(this);
                break;

            case PingMode.LatencyControl:
                this.pingHandler = new LatencyControlPing(this);
                break;

            case PingMode.Manual:
                this.pingHandler = new ManualPing(this);
                break;

            default:
                throw new InvalidOperationException($"Unknown value '{options.PingMode}' for '{nameof(PingMode)}' enumeration.");
            }
        }
Пример #21
0
 /// <summary>
 /// Creates a new instance of <see cref="VtortolaWebSocketTransport"/>
 /// given the endpoint to run at.
 /// </summary>
 /// <param name="endpoint"></param>
 /// <param name="perMessageDeflate">A value indicating whether to support permessage-deflate
 /// compression extension or not.</param>
 /// <param name="certificate">The <see cref="X509Certificate2"/> to use for this transport.</param>
 /// <param name="options">The <see cref="WebSocketListenerOptions"/> to use for the created <see cref="WebSocketListener"/>.</param>
 public VtortolaWebSocketTransport(IPEndPoint endpoint, bool perMessageDeflate, X509Certificate2 certificate = null, WebSocketListenerOptions options = null)
     : this(endpoint, perMessageDeflate, null, certificate, options)
 {
 }
Пример #22
0
 public VtortolaAuthenticatedWebSocketTransport
     (IPEndPoint endpoint, bool perMessageDeflate, ICookieAuthenticatorFactory authenticatorFactory, WebSocketListenerOptions options)
     : this(endpoint, perMessageDeflate, authenticatorFactory, null, options)
 {
 }
        public override WebSocket CreateWebSocket(NetworkConnection networkConnection, WebSocketListenerOptions options, WebSocketHttpRequest httpRequest, WebSocketHttpResponse httpResponse, List <IWebSocketMessageExtensionContext> negotiatedExtensions)
        {
            if (networkConnection == null)
            {
                throw new ArgumentNullException(nameof(networkConnection));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }
            if (httpRequest == null)
            {
                throw new ArgumentNullException(nameof(httpRequest));
            }
            if (httpResponse == null)
            {
                throw new ArgumentNullException(nameof(httpResponse));
            }
            if (negotiatedExtensions == null)
            {
                throw new ArgumentNullException(nameof(negotiatedExtensions));
            }

            return(new WebSocketRfc6455(networkConnection, options, httpRequest, httpResponse, negotiatedExtensions));
        }
 public WebSocketEventListener(IPEndPoint endpoint, WebSocketListenerOptions options)
 {
     _listener = new WebSocketListener(endpoint, options);
     _listener.Standards.RegisterStandard(new WebSocketFactoryRfc6455(_listener));
 }
Пример #25
0
 public VtortolaAuthenticatedWebSocketTransport
     (IPEndPoint endpoint, bool perMessageDeflate, ICookieAuthenticatorFactory authenticatorFactory, X509Certificate2 certificate = null, WebSocketListenerOptions options = null)
     : base(endpoint, perMessageDeflate, authenticatorFactory, certificate, options)
 {
 }
Пример #26
0
 /// <inheritdoc />
 public override Task <Listener> ListenAsync(Uri address, WebSocketListenerOptions options)
 {
     return(Task.FromResult((Listener) new NamedPipeListener(this, address, options)));
 }
        /// <inheritdoc />
        internal override async Task <NetworkConnection> ConnectAsync(Uri address, WebSocketListenerOptions options, CancellationToken cancellation)
        {
            if (address == null)
            {
                throw new ArgumentNullException(nameof(address));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            var remoteEndPoint = this.GetRemoteEndPoint(address);
            var protocolType   = this.GetProtocolType(address, remoteEndPoint);
            // prepare socket
            var socket = new Socket(remoteEndPoint.AddressFamily, SocketType.Stream, protocolType);

            this.SetupClientSocket(socket, remoteEndPoint);
            try
            {
                // prepare connection
                var socketConnectedCondition = new AsyncConditionSource
                {
                    ContinueOnCapturedContext = false
                };
                var socketAsyncEventArgs = new SocketAsyncEventArgs
                {
                    RemoteEndPoint = remoteEndPoint,
                    UserToken      = socketConnectedCondition
                };

                // connect
                socketAsyncEventArgs.Completed += (_, e) => ((AsyncConditionSource)e.UserToken).Set();

                // interrupt connection when cancellation token is set
                var connectInterruptRegistration = cancellation.CanBeCanceled ?
                                                   cancellation.Register(s => ((AsyncConditionSource)s).Interrupt(new OperationCanceledException()), socketConnectedCondition) :
                                                   default(CancellationTokenRegistration);
                using (connectInterruptRegistration)
                {
                    if (socket.ConnectAsync(socketAsyncEventArgs) == false)
                    {
                        socketConnectedCondition.Set();
                    }

                    await socketConnectedCondition;
                }
                cancellation.ThrowIfCancellationRequested();

                // check connection result
                if (socketAsyncEventArgs.ConnectByNameError != null)
                {
                    throw socketAsyncEventArgs.ConnectByNameError;
                }

                if (socketAsyncEventArgs.SocketError != SocketError.Success)
                {
                    throw new WebSocketException($"Failed to open socket to '{address}' due error '{socketAsyncEventArgs.SocketError}'.",
                                                 new SocketException((int)socketAsyncEventArgs.SocketError));
                }

                var localEndPoint = default(EndPoint);
                try
                {
                    localEndPoint = socket.LocalEndPoint;
                }
                catch
                {
                    if (UnixSocketTransport.IsUnixEndPoint(remoteEndPoint))
                    {
                        localEndPoint = remoteEndPoint;
                    }
                }

                var connection = new SocketConnection(socket, localEndPoint);
                socket = null;
                return(connection);
            }
            finally
            {
                if (socket != null)
                {
                    SafeEnd.Dispose(socket, options.Logger);
                }
            }
        }
 public override WebSocket CreateWebSocket(Stream stream, WebSocketListenerOptions options, IPEndPoint localEndpoint, IPEndPoint remoteEndpoint, WebSocketHttpRequest webSocketHttpRequest, List<IWebSocketMessageExtensionContext> negotiatedExtensions)
 {
     return new WebSocketRfc6455(stream, options, localEndpoint, remoteEndpoint, webSocketHttpRequest, negotiatedExtensions);
 }
Пример #29
0
        /// <summary>
        ///     Start the API Server
        /// </summary>
        public static void Start()
        {
            _bufferPoolSize = 100 * _bufferSize;
            PacketLoader.LoadPackets();
            var config = Config.Load();
            var clientUpdateService = new UpdateService();

            clientUpdateService.Start();
            FileSearchService = new FileSearchService(Path.Combine(AppEnvironment.DataPath, "fileIndex.db"));
            FileSearchService.Start();
            CronJobService = new CronJobService(Path.Combine(AppEnvironment.DataPath, "jobs.json"), Path.Combine(AppEnvironment.DataPath, "scripts"));
            CronJobService.ConfigureJobs();
            var apiPort = config.TaskServer.TaskServerPort;

            AllClients         = new ConcurrentDictionary <Guid, AuthClient>();
            ScreenShareService = new ScreenShareService();
            var address         = NetworkService.GetAddress();
            var webCamPort      = config.Webcams.WebcamPort;
            var screenSharePort = config.ScreenShareService.ScreenSharePort;
            var listenEndPoints = new Uri[] {
                new Uri($"ws://{address}:{apiPort}"),
                new Uri($"ws://{address}:{webCamPort}"),
                new Uri($"ws://{address}:{screenSharePort}")
            };
            var options = new WebSocketListenerOptions
            {
                PingMode                 = PingMode.LatencyControl,
                NegotiationTimeout       = TimeSpan.FromSeconds(30),
                PingTimeout              = TimeSpan.FromSeconds(5),
                ParallelNegotiations     = 16,
                NegotiationQueueCapacity = 256,
                BufferManager            = BufferManager.CreateBufferManager(_bufferPoolSize, _bufferSize),
                Logger = NullLogger.Instance,
                HttpAuthenticationHandler = async(request, response) =>
                {
                    await Task.Delay(TimeSpan.FromMilliseconds(1));

                    if (request.Cookies["ConnectionId"] == null)
                    {
                        response.Cookies.Add(new Cookie("ConnectionId", Guid.NewGuid().ToString()));
                    }
                    return(true);
                }
            };

            options.Transports.ConfigureTcp(tcp =>
            {
                tcp.BacklogSize       = 1000; // max pending connections waiting to be accepted
                tcp.ReceiveBufferSize = _bufferSize;
                tcp.SendBufferSize    = _bufferSize;
                tcp.LingerState       = new LingerOption(true, 0);
                tcp.NoDelay           = true;
                tcp.IsAsync           = true;

                tcp.ReceiveTimeout = TimeSpan.FromSeconds(1);
                tcp.SendTimeout    = TimeSpan.FromSeconds(3);
            });

            var server = new WebSocketEventListener(listenEndPoints, options);

            server.OnConnect          += HandleConnect;
            server.OnDisconnect       += HandleDisconnect;
            server.OnPlainTextMessage += HandlePlainTextMessage;
            server.OnEncryptedMessage += HandleEncryptedMessage;
            server.OnError            += HandleError;
            server.Start();
            Log("Api Server started at " + address);
        }
 public WebSocketServer(IPEndPoint endpoint, WebSocketListenerOptions options)
 {
     this.listener = new WebSocketListener(endpoint, options);
     this.listener.Standards.RegisterStandard(new WebSocketFactoryRfc6455(this.listener));
 }
Пример #31
0
        private static void Main(string[] args)
        {
            // configuring logging
            XmlConfigurator.Configure();

            var cancellationTokenSource = new CancellationTokenSource();

            Console.CancelKeyPress += (_, __) => cancellationTokenSource.Cancel();

            Console.WriteLine("Press CTRL+C to stop client.");
            Console.WriteLine("Press ESC to gracefully close connection.");

            var bufferSize     = 1024 * 8;         // 8KiB
            var bufferPoolSize = 100 * bufferSize; // 800KiB pool

            var options = new WebSocketListenerOptions
            {
                // set send buffer size (optional but recommended)
                SendBufferSize = bufferSize,
                // set buffer manager for buffers re-use (optional but recommended)
                BufferManager = BufferManager.CreateBufferManager(bufferPoolSize, bufferSize),
                // set logger, leave default NullLogger if you don't want logging
                Logger = Log
            };

            // register RFC6455 protocol implementation (required)
            options.Standards.RegisterRfc6455();
            // configure tcp transport (optional)
            options.Transports.ConfigureTcp(tcp =>
            {
                tcp.BacklogSize       = 100; // max pending connections waiting to be accepted
                tcp.ReceiveBufferSize = bufferSize;
                tcp.SendBufferSize    = bufferSize;
            });

            var message       = "Hello!";
            var echoServerUrl = new Uri("ws://echo.websocket.org?encoding=text");
            var client        = new vtortola.WebSockets.WebSocketClient(options);

            Log.Warning("Connecting to " + echoServerUrl + "...");
            var webSocket = client.ConnectAsync(echoServerUrl, cancellationTokenSource.Token).Result;

            Log.Warning("Connected to " + echoServerUrl + ". ");

            while (cancellationTokenSource.IsCancellationRequested == false)
            {
                Log.Warning("Sending text: " + message);
                webSocket.WriteStringAsync(message, cancellationTokenSource.Token).Wait();

                var responseText = webSocket.ReadStringAsync(cancellationTokenSource.Token).Result;
                Log.Warning("Received message:" + responseText);

                if (Console.KeyAvailable && Console.ReadKey(intercept: true).Key == ConsoleKey.Escape)
                {
                    break;
                }
                Thread.Sleep(400);
            }

            Log.Warning("Disconnecting from " + echoServerUrl + "...");
            webSocket.CloseAsync().Wait();
            Log.Warning("Disconnected from " + echoServerUrl + ".");

            Log.Warning("Disposing client...");
            client.CloseAsync().Wait();

            Console.WriteLine("Press any key to exit.");
            Console.ReadKey();
        }
Пример #32
0
 /// <summary>
 /// Creates a new instance of <see cref="VtortolaWebSocketTransport"/>
 /// given the endpoint to run at.
 /// </summary>
 /// <param name="endpoint"></param>
 /// <param name="perMessageDeflate">A value indicating whether to support permessage-deflate
 /// compression extension or not.</param>
 /// <param name="options">The <see cref="WebSocketListenerOptions"/> to use for the created <see cref="WebSocketListener"/>.</param>
 public VtortolaWebSocketTransport(IPEndPoint endpoint, bool perMessageDeflate, WebSocketListenerOptions options)
     : this(endpoint, perMessageDeflate, null, options)
 {
 }
Пример #33
0
        protected SocketListener(SocketTransport transport, EndPoint[] endPointsToListen, ProtocolType protocolType, WebSocketListenerOptions options)
        {
            if (endPointsToListen == null)
            {
                throw new ArgumentNullException(nameof(endPointsToListen));
            }
            if (endPointsToListen.Any(p => p == null))
            {
                throw new ArgumentException("Null objects passed in array.", nameof(endPointsToListen));
            }
            if (options == null)
            {
                throw new ArgumentNullException(nameof(options));
            }

            this.log            = options.Logger;
            this.sockets        = EmptySockets;
            this.localEndPoints = EmptyEndPoints;

            var boundSockets    = new Socket[endPointsToListen.Length];
            var boundEndpoints  = new EndPoint[endPointsToListen.Length];
            var activeEvents    = new SocketAsyncEventArgs[endPointsToListen.Length];
            var availableEvents = new SocketAsyncEventArgs[endPointsToListen.Length];

            try
            {
                for (var i = 0; i < boundSockets.Length; i++)
                {
                    boundSockets[i] = new Socket(endPointsToListen[i].AddressFamily, SocketType.Stream, protocolType);
                    boundSockets[i].Bind(endPointsToListen[i]);
                    boundSockets[i].Listen(transport.BacklogSize);
                    boundEndpoints[i]  = boundSockets[i].LocalEndPoint;
                    activeEvents[i]    = CreateSocketAsyncEvent();
                    availableEvents[i] = CreateSocketAsyncEvent();
                }

                this.sockets               = boundSockets;
                this.localEndPoints        = boundEndpoints;
                this.acceptTasks           = new Task <Socket> [boundSockets.Length];
                this.availableAcceptEvents = activeEvents;
                this.activeAcceptEvents    = availableEvents;
                boundSockets               = null;
            }
            finally
            {
                if (boundSockets != null)
                {
                    foreach (var socket in boundSockets)
                    {
                        SafeEnd.Dispose(socket);
                    }
                }
            }
        }
Пример #34
0
 /// <summary>
 /// Creates a new instance of <see cref="VtortolaWebSocketTransport"/>
 /// given the endpoint to run at.
 /// </summary>
 /// <param name="endpoint"></param>
 /// <param name="perMessageDeflate">A value indicating whether to support permessage-deflate
 ///     compression extension or not.</param>
 /// <param name="authenticatorFactory"></param>
 /// <param name="certificate"></param>
 /// <param name="options"></param>
 protected VtortolaWebSocketTransport
     (IPEndPoint endpoint, bool perMessageDeflate, ICookieAuthenticatorFactory authenticatorFactory = null, X509Certificate2 certificate = null, WebSocketListenerOptions options = null)
     : base(authenticatorFactory)
 {
     mEndpoint          = endpoint;
     mPerMessageDeflate = perMessageDeflate;
     mCertificate       = certificate;
     mOptions           = options;
 }
Пример #35
0
        private static void Main(string[] args)
        {
            // configuring logging
            XmlConfigurator.Configure();

            Log.Warning("Starting Echo Server");
            AppDomain.CurrentDomain.UnhandledException += CurrentDomain_UnhandledException;
            TaskScheduler.UnobservedTaskException      += TaskScheduler_UnobservedTaskException;

            // opening TLS certificate
            //X509Store store = new X509Store(StoreName.My, StoreLocation.LocalMachine);
            //store.Open(OpenFlags.ReadOnly);
            //store.Certificates.Count.ToString();
            //var certificate = store.Certificates[1];
            //store.Close();

            var cancellation = new CancellationTokenSource();

            Console.CancelKeyPress += (_, __) => cancellation.Cancel();

            var bufferSize     = 1024 * 8;         // 8KiB
            var bufferPoolSize = 100 * bufferSize; // 800KiB pool

            var options = new WebSocketListenerOptions
            {
                SubProtocols             = new[] { "text" },
                PingTimeout              = TimeSpan.FromSeconds(5),
                NegotiationTimeout       = TimeSpan.FromSeconds(5),
                ParallelNegotiations     = 16,
                NegotiationQueueCapacity = 256,
                BufferManager            = BufferManager.CreateBufferManager(bufferPoolSize, bufferSize),
                Logger = Log
            };

            options.Standards.RegisterRfc6455(factory =>
            {
                factory.MessageExtensions.RegisterDeflateCompression();
            });
            // configure tcp transport
            options.Transports.ConfigureTcp(tcp =>
            {
                tcp.BacklogSize       = 100; // max pending connections waiting to be accepted
                tcp.ReceiveBufferSize = bufferSize;
                tcp.SendBufferSize    = bufferSize;
            });
            // register unix socket transport
            options.Transports.RegisterUnixSockets(unix =>
            {
                unix.ReceiveBufferSize = bufferSize;
                unix.SendBufferSize    = bufferSize;
            });

            // adding the WSS extension
            //options.ConnectionExtensions.RegisterSecureConnection(certificate);

            var listenEndPoints = new Uri[] {
                new Uri("unix:/tmp/wsocket"),
                new Uri("ws://localhost") // will listen both IPv4 and IPv6
            };

            // starting the server
            var server = new WebSocketListener(listenEndPoints, options);

            server.StartAsync().Wait();

            Log.Warning("Echo Server listening: " + string.Join(", ", Array.ConvertAll(listenEndPoints, e => e.ToString())) + ".");
            Log.Warning("You can test echo server at http://www.websocket.org/echo.html.");

            var acceptingTask = AcceptWebSocketsAsync(server, cancellation.Token);

            Log.Warning("Press any key to stop.");
            Console.ReadKey(true);

            Log.Warning("Server stopping.");
            cancellation.Cancel();
            server.StopAsync().Wait();
            acceptingTask.Wait();
        }
Пример #36
0
        public void Benchmark()
        {
            var serializer = new JsonCommonSerializer();

            var port = new Random().Next(30000, 60000);

            var options = new WebSocketListenerOptions();

            options.SubProtocols = new[] { "SignalR" };
            var listener = new WebSocketListener(new IPEndPoint(IPAddress.Loopback, port), options);
            var rfc6455  = new vtortola.WebSockets.Rfc6455.WebSocketFactoryRfc6455(listener);

            listener.Standards.RegisterStandard(rfc6455);
            var serverTransport = listener.GenerateTransportSource();
            var serverRouter    = new DefaultMessageRouter(serverTransport, serializer);

            serverRouter.AddService <ISumService>(new SumService());
            listener.Start();

            var client = new ClientWebSocket();

            client.Options.AddSubProtocol("SignalR");
            var clientTransport = client.GenerateTransportSource();
            var clientRouter    = new DefaultMessageRouter(clientTransport, serializer);
            var proxy           = clientRouter.AddInterface <ISumService>();

            client.ConnectAsync(new Uri("ws://localhost:" + port + "/"), CancellationToken.None).Wait();

            const int randCnt = 100;
            var       rand    = new Random(42);
            var       randoms = new int[randCnt];

            for (int i = 0; i < randCnt; i++)
            {
                randoms[i] = rand.Next(10000000, 20000000);
            }

            var       sw = new Stopwatch();
            long      timeFromClient = 0, timeToClient = 0;
            const int cnt = 1000;

            for (int j = 0; j < cnt; j++)
            {
                sw.Start();
                var sum = proxy.Sum(randoms).Result;
                sw.Stop();
                Assert.Equal(randoms.Sum(), sum);
                for (int i = 0; i < randCnt; i++)
                {
                    randoms[i] = rand.Next(10000000, 20000000);
                }
                var times = proxy.TimeDiff(Stopwatch.GetTimestamp()).Result;
                timeFromClient += times.Item1;
                timeToClient   += Stopwatch.GetTimestamp() - times.Item2;
            }

            _testOutputHelper.WriteLine("Completed {0} sum passes in {1}ms", cnt, sw.ElapsedMilliseconds);
            _testOutputHelper.WriteLine("Client to server latency: {0}us", timeFromClient / cnt / 10);
            _testOutputHelper.WriteLine("Server to client latency: {0}us", timeToClient / cnt / 10);

            sw.Reset();
            var tree = new SumServiceTree();

            SumServiceTree.FillTree(tree, rand, 2);
            _testOutputHelper.WriteLine("Starting large message transfer.");
            sw.Start();
            var result = proxy.Increment(tree).Result;

            sw.Stop();
            Assert.Equal(tree.Leaf + 1, result.Leaf);
            _testOutputHelper.WriteLine("Completed large transfer in {0}ms", sw.Elapsed.TotalMilliseconds);

            clientRouter.Dispose();
            clientTransport.Dispose();
            client.Dispose();

            serverRouter.Dispose();
            serverTransport.Dispose();
            listener.Dispose();
        }
Пример #37
0
 /// <inheritdoc />
 public UnixSocketListener(UnixSocketTransport transport, EndPoint[] endPointsToListen, WebSocketListenerOptions options)
     : base(transport, endPointsToListen, ProtocolType.Unspecified, options)
 {
     this.transport = transport;
 }