Пример #1
0
 public async Task Process(InboundPacket packet)
 {
     foreach (var frame in packet.AsFrames())
     {
         await Process(frame);
     }
 }
Пример #2
0
        /// <summary>
        /// Client has queried the server list
        /// </summary>
        /// <param name="clientRequest"></param>
        private void HandleQuery(InboundPacket clientRequest)
        {
            // Query arrives as an array of QueryData structs
            QueryData[] queries = clientRequest.PopStructArray <QueryData>();

            // Write query to log and notify master server for stats
            LogQuery(queries);

            // Get a filtered list of servers based on the queries which were receieved
            List <Server> servers = serverList.Query(queries);

            // Server count is the first reply following the query and tells the player how many servers to expect
            OutboundPacket serverCountPacket = new OutboundPacket();

            serverCountPacket.Append(servers.Count);
            serverCountPacket.Append((byte)0x01);
            Send(serverCountPacket);

            // Send server list if any were found
            if (servers.Count > 0)
            {
                foreach (Server server in servers)
                {
                    OutboundPacket serverListPacket = new OutboundPacket();
                    serverListPacket.AppendStruct <ServerListEntry>(server.ListEntry);
                    Send(serverListPacket);
                }
            }
        }
Пример #3
0
        /// <summary>
        /// Client has made an unrecognised request
        /// </summary>
        /// <param name="clientRequest"></param>
        private void HandleUnknownRequest(InboundPacket clientRequest)
        {
            clientRequest.Rewind();

            ConnectionLog("UNKNOWN REQUEST CODE={0}", clientRequest.PopByte());
            //MasterServer.Log("Client at {0} sent unrecognised query ", socket.RemoteEndPoint.ToString());
        }
Пример #4
0
        /// <summary>
        /// Handles the player connection, the connection is closed once the request is completed
        /// </summary>
        protected override void Handle()
        {
            try
            {
                InboundPacket  clientRequest     = Receive();
                ClientToMaster clientRequestType = (ClientToMaster)clientRequest.PopByte();

                ConnectionLog("REQUEST TYPE={0}", clientRequestType);

                switch (clientRequestType)
                {
                case ClientToMaster.Query:          HandleQuery(clientRequest);             break;

                case ClientToMaster.GetMOTD:        HandleMOTDRequest(clientRequest);       break;

                case ClientToMaster.QueryUpgrade:   HandleQueryUpgrade(clientRequest);      break;

                default:                            HandleUnknownRequest(clientRequest);    break;
                }
            }
            catch (ThreadAbortException)
            {
                aborted = true;
            }
            catch (Exception) // ex)
            {
                //if (!aborted)
                //    MasterServer.Log("Client connection error: {0}", ex.Message);
            }
        }
Пример #5
0
        /// <summary>
        /// Try to login with the specified details and get the response
        /// </summary>
        /// <param name="cdKey">CD key hash for login</param>
        /// <param name="saltedKey">Salted key hash for login</param>
        /// <param name="type">Remote client type (eg. CLIENT or SERVER)</param>
        /// <param name="version">Remote client version</param>
        /// <param name="locale">Remote client locale</param>
        /// <returns>Login response from the server</returns>
        public string Login(string cdKey, string saltedKey, string type, int version, string locale)
        {
            string response = Protocol.LOGIN_RESPONSE_DENIED;

            if (!connectionError)
            {
                try
                {
                    OutboundPacket login = new OutboundPacket();
                    login.Append(cdKey).Append(saltedKey).Append(type).Append(version);
                    if (type == Protocol.HOST_SERVER)
                    {
                        login.Append(-1);                               // stats enabled flag for server
                    }
                    login.Append((byte)0x04).Append(locale);
                    Send(login);

                    InboundPacket loginResponse = Receive();
                    response = loginResponse.PopString();
                }
                catch
                {
                    connectionError = true;
                }
            }

            Close();

            return(response);
        }
Пример #6
0
        /// <summary>
        /// Overridden so that we can wrap the received data in a ServerInfoPacket instead of an InboundPacket
        /// </summary>
        /// <returns></returns>
        protected override InboundPacket Receive()
        {
            byte[] packetData = ReceieveData();

            InboundPacket packet = (packetData.Length > 4) ? (InboundPacket) new ServerInfoPacket(packetData) : new EmptyInboundPacket();

            outerConnection.OnReceivedPacket(packet);
            return(packet);
        }
Пример #7
0
        /// <summary>
        /// Receive data from the socket and wrap them in an InboundPacket
        /// </summary>
        /// <returns>InboundPacket containing the received data</returns>
        protected virtual InboundPacket Receive()
        {
            byte[] packetData = ReceieveData();

            InboundPacket packet = (packetData.Length > 4) ? new InboundPacket(packetData) : new EmptyInboundPacket();

            OnReceivedPacket(packet);
            return(packet);
        }
Пример #8
0
        /// <summary>
        /// Raise the ReceivedPacket event
        /// </summary>
        /// <param name="packet">Packet that was received</param>
        public void OnReceivedPacket(InboundPacket packet)
        {
            ReceivedPacketEventHandler receivedPacket = this.ReceivedPacket;

            if (receivedPacket != null)
            {
                receivedPacket(this, packet);
            }
        }
Пример #9
0
        /// <summary>
        /// Client has requested the MOTD
        /// </summary>
        /// <param name="clientRequest"></param>
        private void HandleMOTDRequest(InboundPacket clientRequest)
        {
            ConnectionLog("SENDING MOTD");

            // Response packet contains the MOTD string
            OutboundPacket MOTD = new OutboundPacket(MasterServer.GetMOTD(locale, true));

            // Send the MR_OptionalUpgrade value if this connection is valid but player is an outdated version
            if (outerConnection.Version < Protocol.OPTIONALUPGRADE_VERSION)
            {
                MOTD.Append(Protocol.OPTIONALUPGRADE_VERSION);
            }

            // Send the MOTD packet
            Send(MOTD);
        }
Пример #10
0
        /// <summary>
        /// Handles a connection from a CLIENT
        /// </summary>
        /// <param name="login">Login response packet</param>
        protected virtual void HandleClientConnection(InboundPacket login)
        {
            ConnectionLog(Protocol.LOGIN_RESPONSE_APPROVED);
            Send(Protocol.LOGIN_RESPONSE_APPROVED);

            byte osByte = login.PopByte();              // Host's detected operating system

            locale = login.PopString();                 // Host's locale, eg. int, est

            // Map the OS value to the relevant enum value if it's valid
            operatingSystem = Enum.IsDefined(typeof(OperatingSystem), osByte) ? (OperatingSystem)osByte : OperatingSystem.UnknownOS;

            ConnectionLog("{0} OS={1} LOCALE={2}", type, operatingSystem, locale);

            innerConnection = new ClientConnection(this, socket, logWriter, serverList, geoIP, operatingSystem, locale);
            innerConnection.Handle();                   // Handle the connection in this thread
        }
Пример #11
0
        /// <summary>
        /// Establish the connection to the remote master server and get the challenge salt
        /// </summary>
        /// <returns>Master server challenge salt (or 0 on failure)</returns>
        public int Connect()
        {
            int salt = 0;

            try
            {
                socket.Connect(host, port);
                InboundPacket challenge = Receive();
                salt = int.Parse(challenge.PopString());
            }
            catch
            {
                connectionError = true;
            }

            return(salt);
        }
Пример #12
0
        /// <summary>
        /// Handles a connection from a SERVER
        /// </summary>
        /// <param name="login">Login response packet</param>
        protected virtual void HandleServerConnection(InboundPacket login)
        {
            ConnectionLog(Protocol.LOGIN_RESPONSE_APPROVED);
            Send(Protocol.LOGIN_RESPONSE_APPROVED);

            bool bStatLogging = (login.PopInt() == 0);  // Seems to be -1 if disabled, 0 if enabled
            byte osByte       = login.PopByte();        // Host's detected operating system

            locale = login.PopString();                 // Host's locale, eg. int

            // Map the OS value to the relevant enum value if it's valid
            operatingSystem = Enum.IsDefined(typeof(OperatingSystem), osByte) ? (OperatingSystem)osByte : OperatingSystem.UnknownOS;

            ConnectionLog("{0} BSTATLOGGING={1} OS={2} LOCALE={3}", type, bStatLogging, operatingSystem, locale);

            innerConnection = new ServerConnection(this, socket, logWriter, serverList, geoIP, operatingSystem, locale, bStatLogging, md5Manager, cdKeyValidator, gameStats);
            innerConnection.Handle();                   // Handle the connection in this thread
        }
Пример #13
0
        public static async IAsyncEnumerable <InboundPacket> AsDecrypted(this IAsyncEnumerable <InboundEncryptedPacket> encPackets, KeyManager keyMan)
        {
            await foreach (var p in encPackets)
            {
                InboundPacket d = null;
                try
                {
                    if (p is InboundEncryptedHandshakePacket)
                    {
                        await Task.Delay(5000);
                    }
                    d = p.AsDecryptedPacket(keyMan);
                }
                catch
                {
                }

                if (d != null)
                {
                    yield return(d);
                }
            }
        }
Пример #14
0
        /// <summary>
        /// Creates a new player object from information in a received server data packet
        /// </summary>
        /// <param name="packet">Packet containing player information at the current pointer position</param>
        /// <param name="address">Player address, from the server info header</param>
        public Player(Server server, InboundPacket packet, string address)
        {
            Address      = address;
            PlayerNumber = packet.PopInt();         OnPropertyChanged("PlayerNumber");

            if (server.Version > 2225)
            {
                PlayerID = packet.PopInt();         OnPropertyChanged("PlayerID");
            }

            Name    = packet.PopString();     OnPropertyChanged("Name");
            Ping    = packet.PopInt();        OnPropertyChanged("Ping");
            Score   = packet.PopInt();        OnPropertyChanged("Score");
            StatsID = packet.PopInt();        OnPropertyChanged("StatsID");

            if (server.Version > 2225)
            {
                Info = packet.PopKeyValueArray();   OnPropertyChanged("Info");
            }
            else
            {
                Info = new Dictionary <string, string>();
            }
        }
Пример #15
0
        /// <summary>
        /// Handle the connection
        /// </summary>
        protected virtual void Handle()
        {
            try
            {
                // Initialise validation context for this session
                validationContext = cdKeyValidator.BeginValidation("login");

                // Log the new connection to the connection log
                ConnectionLog("ACCEPT LOCALPORT={0} SALT={1}", LocalPort, cdKeyValidator.GetSalt(validationContext));

                // Send the challenge salt
                Send(cdKeyValidator.GetSalt(validationContext).ToString());

                // Read back the authentication from the player
                InboundPacket login = Receive();

                cdKey       = login.PopString();  // Get the first MD5 which should be the CD key hash
                saltedCDKey = login.PopString();  // Get the second MD5 which should be the CD key plus salt hash
                type        = login.PopString();  // Type of client eg. CLIENT or SERVER
                version     = login.PopInt();     // Client's engine version

                // Write the login info to the connection log
                ConnectionLog("CONNECT MD5={0} SALTED={1} TYPE={2} VERSION={3}", cdKey, saltedCDKey, type, version);

                // Set values into the validation context
                validationContext.SetClientInfo(cdKey, saltedCDKey, type, version);

                // Check the CD key
                if (Validate(validationContext))
                {
                    if (version < Protocol.MIN_SUPPORTED_CLIENT_VERSION)
                    {
                        ConnectionLog(Protocol.LOGIN_RESPONSE_UPGRADE);
                        MasterServer.Log("{0} at {1} rejected, outdated version: got {2}", type, (socket.RemoteEndPoint as IPEndPoint).Address.ToString(), version);

                        // This is my best guess for how an UPGRADE packet should be structured, if it's wrong it seems to crash the client
                        OutboundPacket UpgradePacket = new OutboundPacket(Protocol.LOGIN_RESPONSE_UPGRADE);
                        UpgradePacket.Append(Protocol.MIN_SUPPORTED_CLIENT_VERSION);
                        UpgradePacket.Append(0x00);

                        // Send the UPGRADE response
                        Send(UpgradePacket);
                    }
                    else
                    {
                        // Send MSLIST packet if enabled, if the MSLIST is sent successfully then close the
                        // connection (SendMSList() returns true if the MSLIST was sent)
                        if (!SendMSList())
                        {
                            switch (type)
                            {
                            case Protocol.HOST_CLIENT:  HandleClientConnection(login);  break;

                            case Protocol.HOST_SERVER:  HandleServerConnection(login);  break;

                            default:                    HandleUnknownConnection(login); break;
                            }
                        }
                    }
                }
            }
            catch (ThreadAbortException)
            {
                aborted = true;
            }
            catch (Exception ex)
            {
                ConnectionLog("EXCEPTION: {0}", ex.Message);
            }

            try
            {
                socket.Close();
            }
            catch { }

            ConnectionLog("CLOSED");

            ConnectionThreadManager.Remove(Thread.CurrentThread);
            ConnectionManager.DeRegister(this);
        }
Пример #16
0
        /// <summary>
        /// Handle the server connection
        /// </summary>
        protected override void Handle()
        {
            // Loop until connection is closed or forcibly aborted
            while (socket.Connected && !aborted)
            {
                try
                {
                    // Read data from the socket
                    InboundPacket packet = Receive();

                    if (!packet.Empty && packet.Valid)
                    {
                        ServerInfoPacket serverInfo = (ServerInfoPacket)packet;

                        // Connection is considered "established" once the heartbeat has been established
                        switch (State)
                        {
                        // Waiting for initial greeting from the server
                        case ConnectionState.WaitingHello:
                            HandleHello(serverInfo);
                            break;

                        // Waiting to receive heartbeat from the server
                        case ConnectionState.WaitingHeartbeat:
                            if ((DateTime.Now - waitingHeartbeatTime).TotalSeconds > waitForHeartbeatSeconds)
                            {
                                ConnectionLog("TIMEOUT WAITING HEARTBEAT IN STATE {0}", State);
                                MasterServer.Log("[{0}] Timeout waiting for heartbeat response.");
                                outerConnection.Abort();
                            }
                            else
                            {
                                ConnectionLog("UNSOLICITED MESSAGE IN STATE {0}", State);
                            }
                            break;

                        // Connection is established, process inbound packets as normal server conversation
                        case ConnectionState.Established:
                            switch (serverInfo.PacketCode)
                            {
                            case ServerToMaster.ClientResponse:         HandleClientChallengeResponse(serverInfo);  break;

                            case ServerToMaster.GameState:              HandleGameState(serverInfo);                break;

                            case ServerToMaster.Stats:                  HandleStats(serverInfo);                    break;

                            case ServerToMaster.ClientDisconnectFailed: HandleClientDisconnectFailed(serverInfo);   break;

                            case ServerToMaster.MD5Version:             HandleMD5Version(serverInfo);               break;

                            case ServerToMaster.CheckOptionReply:       HandleCheckOptionReply(serverInfo);         break;

                            default:
                                packet.Rewind();
                                ConnectionLog("INVALID MESSAGE STATE={0} CODE={1}", State, packet.PopByte());
                                break;
                            }

                            break;
                        }
                    }
                    else if (socket.Connected)
                    {
                        ConnectionLog("INVALID PACKET STATE={0} DATA={1}", State, packet.PrintBytes(true));
                        Debug.WriteLine(String.Format("Invalid packet from server at {0} in state {1}", server.Address, State));
                        Debug.WriteLine(packet.Print());

                        if (State == ConnectionState.WaitingHeartbeat && (DateTime.Now - waitingHeartbeatTime).TotalSeconds > waitForHeartbeatSeconds)
                        {
                            MasterServer.Log("[{0}] Timeout waiting for heartbeat response.", server);
                            ConnectionLog("TIMEOUT WAITING HEARTBEAT IN STATE {0}", State);
                            outerConnection.Abort();
                        }
                    }
                }
                catch (ThreadAbortException)
                {
                    aborted = true;
                }
                catch (Exception ex)
                {
                    if (!aborted)
                    {
                        ConnectionLog("ERROR: {0}", ex.Message);
                    }

                    break;
                }
            }

            if (!socket.Connected)
            {
                MasterServer.Log("[{0}] Connection closed", server);
            }

            serverList.Remove(server);
            server = null;
        }
Пример #17
0
 /// <summary>
 /// Client has issued an upgrade query. I have no idea of the format of this packet.
 /// </summary>
 /// <param name="clientRequest"></param>
 private void HandleQueryUpgrade(InboundPacket clientRequest)
 {
     //MasterServer.Log("Client at {0} sent CTM_QueryUpgrade", socket.RemoteEndPoint.ToString());
 }
Пример #18
0
 public PacketAnalyser(InboundPacket packet)
 {
     this.packet = packet;
     this.tail   = packet.Print();
 }
Пример #19
0
 /// <summary>
 /// Handles a connection from an unrecognised host type
 /// </summary>
 /// <param name="login">Login response packet</param>
 protected virtual void HandleUnknownConnection(InboundPacket login)
 {
     ConnectionLog("UNRECOGNISED LOGIN TYPE={0}", type);
     MasterServer.Log("Unrecognised LOGIN from {0}. Expecting {1} or {2}, got: '{3}'", (socket.RemoteEndPoint as IPEndPoint).Address.ToString(), Protocol.HOST_SERVER, Protocol.HOST_CLIENT, type);
 }
Пример #20
0
 void InvokedHandleReceivedPacket(TCPConnection connection, InboundPacket packet)
 {
     packets[connection].Packets.Add(new PacketData(packet));
     UpdatePacketList();
 }
Пример #21
0
 void HandleReceivedPacket(TCPConnection connection, InboundPacket packet)
 {
     Invoke(new ReceivedPacketEventHandler(InvokedHandleReceivedPacket), connection, packet);
 }
Пример #22
0
 public PacketData(InboundPacket packet)
 {
     Name     = String.Format("{0} ({1})", DateTime.Now.ToString("dd/MM HH:mm:ss:"), packet.Length);
     Packet   = packet;
     Analyser = new PacketAnalyser(packet);
 }