Пример #1
0
        public async Task Disconnect()
        {
            if (_state == WebSocketConnectionState.Closed)
            {
                return;
            }
            if (_client == null)
            {
                return;
            }
            try
            {
                using (var cts = new CancellationTokenSource(_options.SendTimeout))
                {
                    await _client.CloseAsync(WebSocketCloseStatus.NormalClosure, "Completed", cts.Token);
                }

                _client.Dispose();
                _client = null;
                _state  = WebSocketConnectionState.Closed;
            }
            catch (Exception)
            {
                // If we fail, just ignore it
            }
        }
Пример #2
0
        /// <summary>
        /// Close the connection.
        /// </summary>
        /// <param name="close">The close event arguments.</param>
        /// <param name="send">Is sending.</param>
        /// <param name="wait">Should wait.</param>
        private void Close(CloseEventArgs close, bool send, bool wait)
        {
            lock (_lockConnect)
            {
                // If already closed or closing.
                if (_readyState == WebSocketConnectionState.Closing || _readyState == WebSocketConnectionState.Closed)
                {
                    return;
                }

                // Wait if sending.
                send = send && _readyState == WebSocketConnectionState.Open;
                wait = wait && send;

                // Closing.
                _readyState = WebSocketConnectionState.Closing;
            }

            // Close the handshake.
            close.WasClean = CloseHandshake(
                send ? Frame.CreateCloseFrame(close.PayloadData, _client).ToByteArray() : null,
                wait ? _waitTime : TimeSpan.Zero,
                _client ? (Action)ReleaseClientResources : ReleaseServerResources);

            // Connection state is closed.
            _readyState = WebSocketConnectionState.Closed;
        }
Пример #3
0
 /// <summary>
 /// Check if closable.
 /// </summary>
 /// <param name="state">The web socket state.</param>
 /// <returns>The reason.</returns>
 public static string CheckIfClosable(this WebSocketConnectionState state)
 {
     return(state == WebSocketConnectionState.Closing
            ? "While closing the WebSocket connection."
            : state == WebSocketConnectionState.Closed
              ? "The WebSocket connection has already been closed."
              : null);
 }
 private void WebSocketConnectionOnOnOpened(object sender, EventArgs e)
 {
     Logger.Debug(TAG, $"WebSocket connection opened to:{_wsUrl}");
     _executor.Execute(() =>
     {
         State = WebSocketConnectionState.Connected;
         OnConnectionOpen();
     });
 }
Пример #5
0
 public void Dispose()
 {
     State = WebSocketConnectionState.Closed;
     _pinger?.Dispose();
     _timerCts.Cancel();
     _terminateReceiveCts.Cancel();
     _inbound.Complete();
     _outbound.Complete();
 }
 protected void ReportError(string errorMessage)
 {
     Logger.Error(TAG, errorMessage);
     _executor.Execute(() =>
     {
         if (State == WebSocketConnectionState.Error)
         {
             return;
         }
         State = WebSocketConnectionState.Error;
         _events.OnWebSocketError(errorMessage);
     });
 }
Пример #7
0
        public Task <WebSocketCloseResult> ExecuteAsync(Func <WebSocketFrame, object, Task> messageHandler, object state)
        {
            if (State == WebSocketConnectionState.Closed)
            {
                throw new ObjectDisposedException(nameof(WebSocketConnection));
            }

            if (State != WebSocketConnectionState.Created)
            {
                throw new InvalidOperationException("Connection is already running.");
            }
            State = WebSocketConnectionState.Connected;
            return(ReceiveLoop(messageHandler, state, _terminateReceiveCts.Token));
        }
Пример #8
0
        public static bool IsConnected(this WebSocketConnectionState connectionState)
        {
            try
            {
                return(connectionState.webSocket.Context.WebSocket.IsAlive);
            }
            catch (SocketException)
            {
                return(false);
            }
            catch (Exception ex)
            {
                ex.DebugLog();

                return(false);
            }
        }
Пример #9
0
        public static void Send(SessionState sessionState, WebSocketConnectionState connectionState, string data)
        {
            if (sessionState == null || !sessionState.driver.IsConnected())
            {
                return;
            }

            try
            {
                lock (sessionState.driver)
                {
                    connectionState.webSocket.Send(data);
                }
            }
            catch (Exception ex)
            {
                ex.DebugLog();
            }
        }
Пример #10
0
        private WebSocketCloseResult HandleCloseFrame(ReadableBuffer payload, WebSocketFrame frame, out ushort?actualStatusCode)
        {
            // Update state
            if (State == WebSocketConnectionState.CloseSent)
            {
                State = WebSocketConnectionState.Closed;
            }
            else
            {
                State = WebSocketConnectionState.CloseReceived;
            }

            // Process the close frame
            WebSocketCloseResult closeResult;

            if (!WebSocketCloseResult.TryParse(frame.Payload, out closeResult, out actualStatusCode))
            {
                closeResult = WebSocketCloseResult.Empty;
            }
            return(closeResult);
        }
Пример #11
0
        /// <summary>
        /// Sends a Close frame to the other party. This does not guarantee that the client will send a responding close frame.
        /// </summary>
        /// <remarks>
        /// If the other party does not respond with a close frame, the connection will remain open and the <see cref="Task{WebSocketCloseResult}"/>
        /// will remain active. Call the <see cref="IDisposable.Dispose"/> method on this instance to forcibly terminate the connection.
        /// </remarks>
        /// <param name="result">A <see cref="WebSocketCloseResult"/> with the payload for the close frame</param>
        /// <param name="cancellationToken">A <see cref="CancellationToken"/> that indicates when/if the send is cancelled.</param>
        /// <returns>A <see cref="Task"/> that completes when the close frame has been sent</returns>
        public async Task CloseAsync(WebSocketCloseResult result, CancellationToken cancellationToken)
        {
            if (State == WebSocketConnectionState.Closed)
            {
                throw new ObjectDisposedException(nameof(WebSocketConnection));
            }
            else if (State == WebSocketConnectionState.Created)
            {
                throw new InvalidOperationException("Cannot send close frame when the connection hasn't been started");
            }
            else if (State == WebSocketConnectionState.CloseSent)
            {
                throw new InvalidOperationException("Cannot send multiple close frames");
            }

            var payloadSize = result.GetSize();

            await SendCoreAsync(
                fin : true,
                opcode : WebSocketOpcode.Close,
                payloadAllocLength : payloadSize,
                payloadLength : payloadSize,
                payloadWriter : CloseResultPayloadWriter,
                payload : result,
                cancellationToken : cancellationToken);

            _timerCts.Cancel();
            _pinger?.Dispose();

            if (State == WebSocketConnectionState.CloseReceived)
            {
                State = WebSocketConnectionState.Closed;
            }
            else
            {
                State = WebSocketConnectionState.CloseSent;
            }
        }
Пример #12
0
        /// <summary>
        /// Initialise the members.
        /// </summary>
        private void Init()
        {
            _waitTime   = TimeSpan.FromSeconds(1);
            _readyState = WebSocketConnectionState.Open;

            _messageEventQueue = new Queue <MessageEventArgs>();
            _receiveResult     = new ReceiveResultWebContext()
            {
                ReturnComplete = true
            };
            _lockEnqueue = ((ICollection)_messageEventQueue).SyncRoot;

            if (_context != null)
            {
                // Receive data in async mode.
                _context.Context.Context.ReceivedAsyncMode = () => AsyncModeReceiver();
            }

            _exitReceiving         = new AutoResetEvent(false);
            _receivePong           = new AutoResetEvent(false);
            _recevedFrame          = new AutoResetEvent(false);
            _frameReturnedComplete = new AutoResetEvent(false);
        }
        public void Disconnect(bool waitForComplete)
        {
            CheckIfCalledOnValidThread();
            Logger.Debug(TAG, $"Disconnect WebSocket. State: {State}");
            if (State == WebSocketConnectionState.Registered)
            {
                // Send "bye" to WebSocket server.
                SendByeMessage();
                State = WebSocketConnectionState.Connected;
            }

            if (State == WebSocketConnectionState.Connected || State == WebSocketConnectionState.Error)
            {
                if (waitForComplete)
                {
                    _mre = new ManualResetEvent(false);
                }
                WebSocketConnection.Close();
                State = WebSocketConnectionState.Closed;

                if (waitForComplete)
                {
                    try
                    {
                        _mre.WaitOne(CloseTimeout);
                    }
                    catch (Exception ex)
                    {
                        Logger.Error(TAG, $"Wait error:{ex}");
                    }
                }
            }

            UnWireEvents();

            Logger.Debug(TAG, "Disconnecting WebSocket done.");
        }
Пример #14
0
        public async Task Connect(string remote, WebSocketConnectionOptions options = null)
        {
            if (_state != WebSocketConnectionState.Closed)
            {
                throw new Exception($"Invalid state transition {_state} -> {WebSocketConnectionState.Connecting}");
            }

            if (options == null)
            {
                options = new WebSocketConnectionOptions();
            }

            _state   = WebSocketConnectionState.Connecting;
            _options = options;

            // fix urls with no prefix
            if (!remote.StartsWith("ws://"))
            {
                remote = $"ws://{remote}";
            }

            _client = new ClientWebSocket()
            {
                Options =
                {
                    KeepAliveInterval = _options.KeepAliveInterval
                }
            };

            using (var cts = new CancellationTokenSource(_options.ConnectionTimeout))
            {
                await _client.ConnectAsync(new Uri(remote), cts.Token);
            }

            _state = WebSocketConnectionState.Open;
        }
Пример #15
0
        public static void DropConnection(this WebSocketConnectionState connectionState)
        {
            try
            {
                if (connectionState.sessionState.successfullyConnected)
                {
                    try
                    {
                        using (var dbContext = Database.For <ThePalaceEntities>())
                        {
                            var sqlParam = new SqlParameter("userID", (int)connectionState.sessionState.UserID);
                            dbContext.Database.ExecuteSqlCommand("EXEC Users.FlushUserDetails @userID", sqlParam);
                        }
                    }
                    catch (Exception ex)
                    {
                        ex.DebugLog();
                    }
                }

                try
                {
                    connectionState.webSocket.Context.WebSocket.Close();
                }
                catch (Exception ex)
                {
                    ex.DebugLog();
                }

                try
                {
                    connectionState.Dispose();
                }
                catch (Exception ex)
                {
                    ex.DebugLog();
                }

                if (connectionStates.ContainsKey(connectionState.sessionState.UserID))
                {
                    lock (connectionStates)
                    {
                        if (connectionStates.ContainsKey(connectionState.sessionState.UserID))
                        {
                            connectionStates.Remove(connectionState.sessionState.UserID);
                        }
                    }
                }

                if (SessionManager.sessionStates.ContainsKey(connectionState.sessionState.UserID))
                {
                    lock (SessionManager.sessionStates)
                    {
                        if (SessionManager.sessionStates.ContainsKey(connectionState.sessionState.UserID))
                        {
                            SessionManager.sessionStates[connectionState.sessionState.UserID].Dispose();
                            SessionManager.sessionStates.Remove(connectionState.sessionState.UserID);
                        }
                    }
                }

                if (connectionState.sessionState.successfullyConnected)
                {
                    new Business.MSG_LOGOFF().SendToServer(null, new Message
                    {
                        sessionState = connectionState.sessionState,
                    });
                }

                if (SessionManager.GetRoomUserCount(connectionState.sessionState.RoomID) < 1 && ServerState.roomsCache.ContainsKey(connectionState.sessionState.RoomID))
                {
                    ServerState.roomsCache[connectionState.sessionState.RoomID].Flags &= (~(int)RoomFlags.RF_Closed);
                }
            }
            catch (Exception ex)
            {
                ex.DebugLog();
            }
        }
Пример #16
0
 protected override void OnOpen()
 {
     connectionState = WebAsyncSocket.Accept(this);
 }
Пример #17
0
        public static void Receive(WebSocketConnectionState connectionState, MessageEventArgs e)
        {
            var floodControlThreadshold_InMilliseconds = ConfigManager.GetValue <int>("FloodControlThreadshold_InMilliseconds", 1000).Value;
            var floodControlThreadshold_RawCount       = ConfigManager.GetValue <int>("FloodControlThreadshold_RawCount", 100).Value;
            //var floodControlThreadshold_RawSize = ConfigManager.GetValue<int>("FloodControlThreadshold_RawSize", ???).Value;
            var floodControlThreadshold_TimeSpan = new TimeSpan(0, 0, 0, 0, floodControlThreadshold_InMilliseconds);

            var sessionState  = connectionState.sessionState;
            var handler       = connectionState.webSocket;
            var bytesReceived = e.Data?.Length ?? 0;
            var data          = e.Data;

            if (bytesReceived > 0)
            {
                connectionState.lastActivity = DateTime.UtcNow;

                if (!sessionState.Authorized)
                {
                    #region Flood Control
                    connectionState.floodControl[DateTime.UtcNow] = bytesReceived;
                    //var rawSize = state.floodControl.Values.Sum();

                    var expired = connectionState.floodControl
                                  .Where(f => f.Key > DateTime.UtcNow.Subtract(floodControlThreadshold_TimeSpan))
                                  .Select(f => f.Key)
                                  .ToList();

                    expired.ForEach(f =>
                    {
                        connectionState.floodControl.Remove(f);
                    });

                    if (connectionState.floodControl.Count > floodControlThreadshold_RawCount)
                    {
                        ThePalace.Core.Utility.Logger.Log(MessageTypes.Info, $"Disconnect[{sessionState.UserID}]: Flood Control", "WebAsyncSocket.Receive()");

                        new Business.MSG_SERVERDOWN
                        {
                            reason     = ServerDownFlags.SD_Flood,
                            whyMessage = "Flood Control!",
                        }.Send(null, new Message
                        {
                            sessionState = sessionState,
                        });

                        connectionState.DropConnection();

                        return;
                    }
                    #endregion
                }

                if (bytesReceived > 0)
                {
                    try
                    {
                        connectionState.header = new Header();
                        connectionState.header.DeserializeJSON(data);
                    }
                    catch { }

                    var mnemonic = Regex.Replace(connectionState.header.eventType, @"[^\w\d]+", string.Empty);
                    var type     = PluginManager.GetType($"ThePalace.Server.Plugins.Protocols.{mnemonic}");
                    var message  = (Message)null;

                    if (type == null)
                    {
                        type = Type.GetType($"ThePalace.Server.Protocols.{connectionState.header.eventType}");
                    }

                    if (type == null)
                    {
                        new Business.MSG_SERVERDOWN
                        {
                            reason     = ServerDownFlags.SD_CommError,
                            whyMessage = "Communication Error!",
                        }.Send(null, new Message
                        {
                            sessionState = sessionState,
                        });

                        connectionState.DropConnection();
                    }

                    if (type != null)
                    {
                        message = new Message
                        {
                            protocol     = (IReceiveProtocol)Activator.CreateInstance(type),
                            header       = new Header(connectionState.header),
                            sessionState = sessionState,
                        };
                    }

                    if (message != null)
                    {
                        try
                        {
                            message.protocol.DeserializeJSON(connectionState.header.message);

                            lock (SessionManager.messages)
                            {
                                SessionManager.messages.Enqueue(message);

                                ThreadController.manageMessagesQueueSignalEvent.Set();
                            }
                        }
                        catch (Exception ex)
                        {
                            ex.DebugLog();
                        }

                        connectionState.lastPinged         = null;
                        connectionState.lastPacketReceived = DateTime.UtcNow;
                    }
                }
            }
            else if (!connectionState.IsConnected())
            {
                connectionState.DropConnection();
            }
        }