Ejemplo n.º 1
0
        /// <summary>
        /// Send updated MD5 data to the server
        /// </summary>
        /// <param name="updates">List of MD5 data to send</param>
        public virtual void SendMD5Updates(List <MD5Entry> updates)
        {
            MasterServer.Log("[{0}] Updating MD5 database to revision {1}", server, md5Manager.maxRevision);

            int index = 0;

            while (index < updates.Count)
            {
                int updatesInPacket = Math.Min(updates.Count - index, Protocol.MAX_MD5_UPDATES_PER_PACKET);

                OutboundPacket MD5UpdatePacket = new OutboundPacket((byte)MasterToServer.MD5Update);

                MD5UpdatePacket.Append((byte)updatesInPacket);

                for (int offset = 0; offset < updatesInPacket; offset++)
                {
                    MD5UpdatePacket.Append(updates[index + offset].PackageGUID);
                    MD5UpdatePacket.Append(updates[index + offset].PackageMD5);
                    MD5UpdatePacket.Append(updates[index + offset].Revision);
                }

                ConnectionLog("SENDING MTS_MD5UPDATE COUNT={0}", updatesInPacket);
                Send(MD5UpdatePacket);

                index += updatesInPacket;
            }
        }
Ejemplo n.º 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);
                }
            }
        }
Ejemplo n.º 3
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);
        }
Ejemplo n.º 4
0
        public void Send(OutboundPacket packet)
        {
            Log.Verbose("Sending {rawPacket}", packet.Raw);
            Log.Debug("<- {packet}", packet);

            Connection?.Send(Encoding.ASCII.GetBytes(packet.Raw));
        }
Ejemplo n.º 5
0
 /// <summary>
 /// Send the specified outbound packet to the socket
 /// </summary>
 /// <param name="packet"></param>
 protected virtual void Send(OutboundPacket packet)
 {
     if (packet != null && packet.Type == OutboundPacketType.TCP && packet.Length > 0 && socket != null && socket.Connected)
     {
         socket.Send(packet);
     }
 }
Ejemplo n.º 6
0
        /// <summary>
        /// Check INI option on the remote server, remote server will reply with STM_CheckOptionReply
        /// </summary>
        /// <param name="packageName">Name of package and group</param>
        /// <param name="variableName">Variable name</param>
        public virtual void CheckOption(string packageName, string variableName)
        {
            OutboundPacket CheckOptionPacket = new OutboundPacket((byte)MasterToServer.CheckOption);

            CheckOptionPacket.Append(packageName);
            CheckOptionPacket.Append(variableName);
            Send(CheckOptionPacket);
        }
Ejemplo n.º 7
0
        /// <summary>
        /// Set the remote server's match ID
        /// </summary>
        /// <param name="MatchID">Match ID to set on the remote server</param>
        public virtual void SendMatchID(int MatchID)
        {
            ConnectionLog("ASSIGNING MATCH ID {0}", MatchID);

            OutboundPacket MatchIDPacket = new OutboundPacket((byte)MasterToServer.MatchID);

            MatchIDPacket.Append(MatchID);
            Send(MatchIDPacket);
        }
Ejemplo n.º 8
0
        /// <summary>
        /// Set INI file option on the remote server
        /// </summary>
        /// <param name="packageName">Name of package and group</param>
        /// <param name="variableName">Variable name</param>
        /// <param name="value">Value to set</param>
        public virtual void SetOption(string packageName, string variableName, string value)
        {
            OutboundPacket SetOptionPacket = new OutboundPacket((byte)MasterToServer.UpdateOption);

            SetOptionPacket.Append(packageName);
            SetOptionPacket.Append(variableName);
            SetOptionPacket.Append(value);
            Send(SetOptionPacket);
        }
Ejemplo n.º 9
0
        /// <summary>
        /// Receieved all heartbeats okay, send acknowledgment to server
        /// </summary>
        /// <param name="unknown">Not sure what this value is for, seems to always be 120</param>
        protected virtual void SendHeartbeatAcknowledgment(int unknown)
        {
            OutboundPacket HeartbeatExitPacket = new OutboundPacket(Protocol.HEARTBEAT_RESPONSE_CMD);

            HeartbeatExitPacket.Append(unknown);    // Always 120 ?
            HeartbeatExitPacket.Append(server.QueryPort);
            HeartbeatExitPacket.Append(server.Port);
            HeartbeatExitPacket.Append(server.GamespyQueryPort);
            Send(HeartbeatExitPacket);
        }
Ejemplo n.º 10
0
        /// <summary>
        /// Disconnect the specified player (eg. because of failed challenge or invalid CD key)
        /// </summary>
        /// <param name="clientAddress">Address of the player to disconnect, in IP:port notation</param>
        public virtual void DisconnectClient(string clientAddress)
        {
            ConnectionLog("SENDING MTS_CLIENTAUTHFAILED CLIENT={0}", clientAddress);
            MasterServer.Log("[{0}] Sending MTS_ClientAuthFailed to {1}", server, clientAddress);

            OutboundPacket DisconnectClientPacket = new OutboundPacket((byte)MasterToServer.ClientAuthFailed);

            DisconnectClientPacket.Append(clientAddress);
            Send(DisconnectClientPacket);
        }
Ejemplo n.º 11
0
 /// <summary>
 /// Send a packet to a remote host
 /// </summary>
 /// <param name="udp">UDP client to use</param>
 /// <param name="packet">Packet to send</param>
 protected virtual void Send(UdpClient udp, OutboundPacket packet)
 {
     if (packet != null && packet.Type == OutboundPacketType.UDP && packet.Length > 0 && udp != null && remoteEndpoint != null)
     {
         udp.Send(packet, packet.FullLength, remoteEndpoint);
     }
     else
     {
         throw new ArgumentException("Cannot send a null, empty, or TCP packet on a UDP socket");
     }
 }
Ejemplo n.º 12
0
        /// <summary>
        /// Master server requests heartbeat blah with code blah
        /// </summary>
        /// <param name="type">Type of heartbeat to request</param>
        /// <param name="code">Heartbeat code to request</param>
        protected virtual void SendHeartbeatRequest(HeartbeatType type, int code)
        {
            if (State == ConnectionState.WaitingHello)
            {
                OutboundPacket HeartbeatPacket = new OutboundPacket();

                HeartbeatPacket.Append(Protocol.HEARTBEAT_CMD);
                HeartbeatPacket.Append((byte)type);
                HeartbeatPacket.Append(code);

                waitingHearbeats.Add(type);

                Send(HeartbeatPacket);
            }
        }
Ejemplo n.º 13
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);
        }
Ejemplo n.º 14
0
        /// <summary>
        /// Challenge the specified player to return its CD key and the salted CD key
        /// </summary>
        /// <param name="clientAddress">Address of the player to challenge, in IP:port notation</param>
        public virtual void ChallengeClient(string clientAddress)
        {
            if (clientAddress != "" && clientAddress != "local")
            {
                ConnectionLog("SENDING MTS_CLIENTCHALLENGE CLIENT={0}", clientAddress);
                MasterServer.Log("[{0}] Sending MTS_ClientChallenge to {1}", server, clientAddress);

                ValidationContext clientValidationContext = cdKeyValidator.BeginValidation(clientAddress);
                validationContexts[clientAddress] = clientValidationContext;

                OutboundPacket ChallengeClientPacket = new OutboundPacket((byte)MasterToServer.ClientChallenge);
                ChallengeClientPacket.Append(clientAddress);
                ChallengeClientPacket.Append(clientValidationContext.Salt.ToString());
                Send(ChallengeClientPacket);
            }
            else
            {
                MasterServer.Log("Unable to send MTS_ClientChallenge. Cannot challenge local player");
            }
        }
Ejemplo n.º 15
0
        /// <summary>
        /// Thread function where the query is actually executed. The call to Receive() is blocking and the
        /// separate timer thread takes care of the timeout behaviour (if specified)
        /// </summary>
        private void QueryThreadProc(object oQueryState)
        {
            UDPServerQueryState queryState = (UDPServerQueryState)oQueryState;

            try
            {
                // Send the query to the server
                OutboundPacket query = new OutboundPacket(true);
                query.Append((byte)queryState.QueryType);
                Send(queryState.QueryClient, query);

                // Wait for a response from the server
                UDPPacket queryResponse = Receive(queryState.QueryClient);

                // Stop the timeout timer
                queryState.End();

                if (queryState.QueryResponse == UDPServerQueryResponse.None)
                {
                    queryState.QueryResponse = UDPServerQueryResponse.Success;
                    OnQueryFinished(queryState, queryResponse);
                }
            }
            catch (ThreadAbortException) { }
            catch (Exception)
            {
                if (queryState.QueryResponse != UDPServerQueryResponse.Timeout)
                {
                    queryState.QueryResponse = UDPServerQueryResponse.Error;

                    // Stop the timeout timer
                    queryState.End();
                    OnQueryFinished(queryState, null);
                }
            }

            lock (activeQueryLock)
            {
                activeQueries.Remove(queryState);
            }
        }
Ejemplo n.º 16
0
        /// <summary>
        /// Poke raw data down the connection, used for testing purposes
        /// </summary>
        /// <param name="command"></param>
        public void Poke(string[] command)
        {
            OutboundPacket ob = new OutboundPacket();
            byte           b  = 0x00;

            for (int i = 1; i < command.Length; i++)
            {
                if (byte.TryParse(command[i], out b))
                {
                    ob.Append(b);
                }
                else
                {
                    ob.Append(command[i]);
                }
            }

            ConnectionLog("POKE {0}", ob.Print());

            Send(ob);
        }
Ejemplo n.º 17
0
        /// <summary>
        /// Send the updated MS list to the remote client
        /// </summary>
        /// <returns>True if the packet was sent ok</returns>
        protected virtual bool SendMSList()
        {
            // Check whether we should send the MSLIST message on this port
            if (MSListEnabled)
            {
                // Calculate the number of entries we need to send
                int msListEntryCount = Math.Min(Math.Min(MasterServer.Settings.MSListServers.Length, MasterServer.Settings.MSListPorts.Length), MasterServer.Settings.MSListMaxServers);

                // Only send the list if there are entries to send
                if (msListEntryCount > 0)
                {
                    ConnectionLog("{0} COUNT={1}", Protocol.LOGIN_RESPONSE_MSLIST, msListEntryCount);

                    // Create MSLIST packet
                    OutboundPacket msListPacket = new OutboundPacket(Protocol.LOGIN_RESPONSE_MSLIST);

                    // Append server addresses
                    msListPacket.Append((byte)msListEntryCount);
                    for (int entry = 0; entry < msListEntryCount; entry++)
                    {
                        msListPacket.Append(MasterServer.Settings.MSListServers[entry]);
                    }

                    // Append server ports
                    msListPacket.Append((byte)msListEntryCount);
                    for (int entry = 0; entry < msListEntryCount; entry++)
                    {
                        msListPacket.Append((int)MasterServer.Settings.MSListPorts[entry]);
                    }

                    // Send packet to the remote host
                    Send(msListPacket);
                    return(true);
                }
            }

            return(false);
        }
Ejemplo n.º 18
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);
        }