Beispiel #1
0
        /// <summary>
        /// Logs the client out of the game client, and closes the stream
        /// </summary>
        /// <param name="reason">
        /// The disconnect reason code.
        /// </param>
        /// <remarks>
        /// If set the <paramref name="reason"/> is set to <see cref="DisconnectReason.ForcedServerShutdown"/>,
        /// the OnDisconect event will not be called, the database will not be updated to reset everyone's session code,
        /// and the EventArgs objects will NOT be returned to the IO pool. You should only set to
        /// <see cref="DisconnectReason.ForcedServerShutdown"/> for a planned server shutdown.
        /// </remarks>
        public void Disconnect(DisconnectReason reason)
        {
            // Update database session
            if (Status == LoginStatus.Completed && reason != DisconnectReason.ForcedServerShutdown)
            {
                try
                {
                    using (GamespyDatabase Database = new GamespyDatabase())
                        Database.Execute("UPDATE player SET online=0 WHERE id=" + PlayerId);
                }
                catch { }
            }

            // If connection is still alive, disconnect user
            try
            {
                Stream.OnDisconnect -= Stream_OnDisconnect;
                Stream.DataReceived -= Stream_DataReceived;
                Stream.Close(reason == DisconnectReason.ForcedServerShutdown);
            }
            catch { }

            // Set status and log
            if (Status == LoginStatus.Completed)
            {
                if (reason == DisconnectReason.NormalLogout)
                {
                    ServerManager.Log(
                        "Client Logout:  {0} - {1} - {2}",
                        PlayerNick,
                        PlayerId,
                        RemoteEndPoint
                        );
                }
                else
                {
                    ServerManager.Log(
                        "Client Disconnected:  {0} - {1} - {2}, Code={3}",
                        PlayerNick,
                        PlayerId,
                        RemoteEndPoint,
                        Enum.GetName(typeof(DisconnectReason), reason)
                        );
                }
            }

            // Preapare to be unloaded from memory
            Status = LoginStatus.Disconnected;
            Dispose();

            // Call disconnect event
            OnDisconnect?.Invoke(this);
        }
        /// <summary>
        /// Starts the Login Server listeners, and begins accepting new connections
        /// </summary>
        public static void StartServers()
        {
            // Make sure we arent already running!
            if (isRunning)
            {
                return;
            }

            try
            {
                // Start the DB Connection
                Console.Write("Connecting to Mysql... ");
                using (GamespyDatabase Database = new GamespyDatabase())
                {
                    Console.Write("Success!" + Environment.NewLine);

                    // Reset game sessions
                    if (Config.GetType <bool>("Settings", "ResetGameSessionsOnStartup"))
                    {
                        Console.Write("Resetting all game sessions... ");
                        Database.Execute("UPDATE web_users SET game_session=0 WHERE id > 0");
                        Console.Write("Success!" + Environment.NewLine);
                    }
                }

                // Create our end point to bind to
                int       port    = Config.GetType <int>("Settings", "LoginServerPort");
                IPAddress address = IPAddress.Parse(Config.GetValue("Settings", "ServerBindIp"));

                // Start the Client Manager Server
                Console.Write("<GPCM> Binding to TCP port {0}... ", port);
                CmServer = new GpcmServer(new IPEndPoint(address, port));
                Console.Write("Success!" + Environment.NewLine);

                // Start Search Provider Server
                Console.Write("<GPSP> Binding to TCP port {0}... ", ++port);
                SpServer = new GpspServer(new IPEndPoint(address, port));
                Console.Write("Success!" + Environment.NewLine);
            }
            catch
            {
                Console.Write("Failed!" + Environment.NewLine);
                throw;
            }

            // Let the client know we are ready for connections
            isRunning = true;
        }
Beispiel #3
0
        /// <summary>
        /// Logs the client out of the game client, and closes the stream
        /// </summary>
        /// <param name="where">
        /// The disconnect code. If set to 9, the OnDisconect event will not be called, the database
        /// will not be updated to reset everyone's session code, and the EventArgs objects will NOT
        /// be returned to the IO pool. You should only set to 9 for a planned server shutdown.
        /// </param>
        /// <remarks>
        ///   Codes:
        ///     0 => Client sends the "logout" command
        ///     1 => Keep Alive Packet failed to send (may not work with new async socket code)
        ///     2 => Invalid login query, or username was incorrect
        ///     3 => Incorrect Password
        ///     4 => An error occured while trying to login the client (could be database related)
        ///     5 => Cant create account, username exists already
        ///     6 => Error Creating new account in database
        ///     7 => Invalid query for account creation, or an exception was thrown while trying to create account
        ///     8 => Stream Disconnected
        ///     9 => Forced server shutdown [No events called, database sessions are not updated, and EventArgs are disposed]
        ///     10 => Client challenge already sent
        /// </remarks>
        public void Disconnect(int where)
        {
            // Update database session
            if (Status == LoginStatus.Completed && where < 9)
            {
                try
                {
                    using (GamespyDatabase Database = new GamespyDatabase())
                        Database.Execute("UPDATE web_users SET game_session=0 WHERE pid=" + PlayerId);
                }
                catch { }
            }

            // If connection is still alive, disconnect user
            try
            {
                Stream.OnDisconnect -= Stream_OnDisconnect;
                Stream.DataReceived -= Stream_DataReceived;
                Stream.Close(where == 9);
            }
            catch { }

            // Set status and log
            if (Status == LoginStatus.Completed)
            {
                ServerManager.Log("Client Logout:  {0} - {1} - {2}, Code={3}", PlayerNick, PlayerId, RemoteEndPoint, where);
            }

            // Preapare to be unloaded from memory
            Status = LoginStatus.Disconnected;
            Dispose();

            // Call disconnect event
            if (OnDisconnect != null)
            {
                OnDisconnect(this);
            }
        }
Beispiel #4
0
        /// <summary>
        /// This method verifies the login information sent by
        /// the client, and returns encrypted data for the client
        /// to verify as well
        /// </summary>
        public void ProcessLogin(Dictionary <string, string> Recv)
        {
            // Make sure we have all the required data to process this login
            if (!Recv.ContainsKey("uniquenick") || !Recv.ContainsKey("challenge") || !Recv.ContainsKey("response"))
            {
                Stream.SendAsync(@"\error\\err\0\fatal\\errmsg\Invalid Query!\id\1\final\");
                Disconnect(2);
                return;
            }

            // Dispose connection after use
            try
            {
                using (GamespyDatabase Conn = new GamespyDatabase())
                {
                    // Try and fetch the user from the database
                    Dictionary <string, object> User = Conn.GetUser(Recv["uniquenick"]);
                    if (User == null)
                    {
                        Stream.SendAsync(@"\error\\err\265\fatal\\errmsg\The uniquenick provided is incorrect!\id\1\final\");
                        Disconnect(2);
                        return;
                    }

                    // Set player variables
                    PlayerId          = Int32.Parse(User["pid"].ToString());
                    PlayerNick        = Recv["uniquenick"];
                    PlayerEmail       = User["email"].ToString();
                    PlayerCountryCode = User["game_country"].ToString();
                    PasswordHash      = User["password"].ToString().ToLowerInvariant();

                    // Use the GenerateProof method to compare with the "response" value. This validates the given password
                    if (Recv["response"] == GenerateProof(Recv["challenge"], ServerChallengeKey))
                    {
                        // Create session key
                        SessionKey = Crc.ComputeChecksum(PlayerNick);

                        // Password is correct
                        Stream.SendAsync(
                            @"\lc\2\sesskey\{0}\proof\{1}\userid\{2}\profileid\{2}\uniquenick\{3}\lt\{4}__\id\1\final\",
                            SessionKey,
                            GenerateProof(ServerChallengeKey, Recv["challenge"]), // Do this again, Params are reversed!
                            PlayerId,
                            PlayerNick,
                            GenerateRandomString(22) // Generate LT whatever that is (some sort of random string, 22 chars long)
                            );

                        // Log Incoming Connections
                        ServerManager.Log("Client Login:   {0} - {1} - {2}", PlayerNick, PlayerId, RemoteEndPoint);
                        Conn.Execute(
                            "UPDATE web_users SET last_game_ip=@P0, game_session=1, game_tstamp=@P1 WHERE pid=@P2",
                            RemoteEndPoint.Address,
                            DateTime.UtcNow.ToUnixTimestamp(),
                            PlayerId
                            );

                        // Update status last, and call success login
                        Status = LoginStatus.Completed;
                        if (OnSuccessfulLogin != null)
                        {
                            OnSuccessfulLogin(this);
                        }
                    }
                    else
                    {
                        // Log Incoming Connections
                        ServerManager.Log("Failed Login Attempt: {0} - {1} - {2}", PlayerNick, PlayerId, RemoteEndPoint);

                        // Password is incorrect with database value
                        Stream.SendAsync(@"\error\\err\260\fatal\\errmsg\The password provided is incorrect.\id\1\final\");
                        Disconnect(3);
                    }
                }
            }
            catch (Exception ex)
            {
                ExceptionHandler.GenerateExceptionLog(ex);
                Disconnect(4);
                return;
            }
        }