This class represents a packet recieved from and/or to be sent to a remote UDP connection. This class is essentially a wrapper for SocketAsyncEventArgs and Asynchronous reading and writing
Example #1
0
        /// <summary>
        /// Sends the specified packets data to the client, and releases the resources
        /// </summary>
        /// <param name="Packet"></param>
        protected void ReplyAsync(GamespyUdpPacket Packet)
        {
            // If we are shutting down, dont receive again
            if (!IsRunning)
            {
                return;
            }

            Listener.SendToAsync(Packet.AsyncEventArgs);
        }
        /// <summary>
        /// Called when a connection comes in on the CDKey server
        /// </summary>
        /// known messages
        ///  \ka\ = keep alive from the game server every 20s, we don't care about this
        ///  \auth\ ... = authenticate cd key, this is what we care about
        ///  \disc\ ... = disconnect cd key, because there's checks if the cd key is in use, which we don't care about really, but we could if we wanted to
        /// </remarks>
        protected override void ProcessAccept(GamespyUdpPacket Packet)
        {
            // If we dont reply, we must manually release the EventArgs back to the pool
            bool replied = false;

            try
            {
                // Decrypt message
                IPEndPoint remote = (IPEndPoint)Packet.AsyncEventArgs.RemoteEndPoint;
                string decrypted = Xor(Encoding.UTF8.GetString(Packet.BytesRecieved)).Trim('\\');

                // Ignore keep alive pings
                if (!decrypted.StartsWith("ka"))
                {
                    Dictionary<string, string> recv = ConvertToKeyValue(decrypted.Split('\\'));
                    if (recv.ContainsKey("auth") && recv.ContainsKey("resp") && recv.ContainsKey("skey"))
                    {
                        // Normally you would check the CD key database for the CD key MD5, but we arent Gamespy, we dont care
                        DebugLog.Write("CDKey Check Requested from: {0}:{1}", remote.Address, remote.Port);
                        string reply = String.Format(@"\uok\\cd\{0}\skey\{1}", recv["resp"].Substring(0, 32), recv["skey"]);

                        // Set new packet contents, and send a reply
                        Packet.SetBufferContents(Encoding.UTF8.GetBytes(Xor(reply)));
                        base.ReplyAsync(Packet);
                        replied = true;
                    }
                    else if (recv.ContainsKey("disc"))
                    {
                        // Handle, User disconnected from server
                    }
                    else
                    {
                        DebugLog.Write("Incomplete or Invalid CDKey Packet Received: " + decrypted);
                    }
                }
            }
            catch (Exception E)
            {
                Program.ErrorLog.Write("ERROR: [MasterServer.CDKeySocket_OnDataReceived] " + E.Message);
            }
            finally
            {
                // Release so that we can pool the EventArgs to be used on another connection
                if (!replied)
                    base.Release(Packet.AsyncEventArgs);
            }
        }
        /// <summary>
        /// Callback method for when the UDP Master socket recieves a connection
        /// </summary>
        protected override void ProcessAccept(GamespyUdpPacket Packet)
        {
            IPEndPoint remote = (IPEndPoint)Packet.AsyncEventArgs.RemoteEndPoint;

            // Need at least 5 bytes
            if (Packet.BytesRecieved.Length < 5)
            {
                base.Release(Packet.AsyncEventArgs);
                return;
            }

            // Handle request in a new thread
            Task.Run(() =>
            {
                // If we dont reply, we must manually release the pool
                bool replied = false;

                try
                {
                    // Both the clients and servers will send a Gamespy Available Heartbeat Check
                    // When starting Battlefield 2, the client will send 7 heartbeat checks
                    if (Packet.BytesRecieved[0] == 0x09 && Packet.BytesRecieved.SequenceEqual(BF2AvailableRequest))
                    {
                        DebugLog.Write("BF2Available Called From {0}:{1}", remote.Address, remote.Port);

                        // Send back a generic reply.
                        Packet.SetBufferContents(BF2AvailableReply);
                        base.ReplyAsync(Packet);
                        replied = true;
                    }
                    else if (Packet.BytesRecieved[0] == 0x03 && Program.Config.GamespyEnableServerlist)
                    {
                        // === this is where server details come in, it starts with 0x03, it happens every 60 seconds or so
                        // If we aren't validated (initial connection), send a challenge key
                        if (!ParseServerDetails(remote, Packet.BytesRecieved.Skip(5).ToArray()))
                        {
                            DebugLog.Write("Sending Server Challenge to {0}:{1}", remote.Address, remote.Port);

                            // this should be some sort of proper encrypted challenge, but for now i'm just going to hard code
                            // it because I don't know how the encryption works...
                            byte[] uniqueId = Packet.BytesRecieved.Skip(1).Take(4).ToArray();
                            Packet.SetBufferContents(new byte[]
                            {
                                0xfe, 0xfd, 0x01, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3], 0x44, 0x3d, 0x73,
                                0x7e, 0x6a, 0x59, 0x30, 0x30, 0x37, 0x43, 0x39, 0x35, 0x41, 0x42, 0x42, 0x35, 0x37, 0x34,
                                0x43, 0x43, 0x00
                            });
                            base.ReplyAsync(Packet);
                            replied = true;
                        }
                    }
                    else if (Packet.BytesRecieved[0] == 0x01 && Program.Config.GamespyEnableServerlist)
                    {
                        // === this is a challenge response, it starts with 0x01
                        if (Packet.BytesRecieved.Skip(5).SequenceEqual(ServerValidateCode))
                        {
                            DebugLog.Write("Server Challenge Recieved and Validated: {0}:{1}", remote.Address, remote.Port);

                            // Send back a good response if we validate successfully
                            if (ValidateServer(remote))
                            {
                                byte[] uniqueId = Packet.BytesRecieved.Skip(1).Take(4).ToArray();
                                Packet.SetBufferContents(new byte[] { 0xfe, 0xfd, 0x0a, uniqueId[0], uniqueId[1], uniqueId[2], uniqueId[3] });
                                base.ReplyAsync(Packet);
                                replied = true;
                            }
                        }
                        else
                            DebugLog.Write("Server Challenge Received and FAILED Validation: {0}:{1}", remote.Address, remote.Port);
                    }
                    else if (Packet.BytesRecieved[0] == 0x08 && Program.Config.GamespyEnableServerlist)
                    {
                        // this is a server ping, it starts with 0x08, it happens every 20 seconds or so
                        string key = String.Format("{0}:{1}", remote.Address, remote.Port);
                        GameServer server;
                        if (Servers.TryGetValue(key, out server) && server.IsValidated)
                        {
                            DebugLog.Write("Server Heartbeat Received: " + key);

                            // Update Ping
                            server.LastPing = DateTime.Now;
                            Servers.AddOrUpdate(key, server, (k, old) => { return server; });
                        }
                        else
                            DebugLog.Write("Server Heartbeat Received from Unvalidated Server: " + key);
                    }
                }
                catch (Exception E)
                {
                    Program.ErrorLog.Write("ERROR: [MasterUdpServer.ProcessAccept] " + E.Message);
                }

                // Release so that we can pool the EventArgs to be used on another connection
                if (!replied)
                    base.Release(Packet.AsyncEventArgs);
            });
        }
Example #4
0
 /// <summary>
 /// When a new connection is established, the parent class is responsible for
 /// processing the connected client
 /// </summary>
 /// <param name="Stream">A GamespyTcpStream object that wraps the I/O AsyncEventArgs and socket</param>
 protected abstract void ProcessAccept(GamespyUdpPacket Packet);