This object is used as a Network Stream wrapper for Gamespy TCP protocol,
Inheritance: IDisposable
        /// <summary>
        /// Constructor
        /// </summary>
        public GpspClient(GamespyTcpStream client)
        {
            // Set disposed to false!
            this.Disposed = false;

            // Generate a unique name for this connection
            this.ConnectionId = Interlocked.Increment(ref SessionsCreated);

            // Init a new client stream class
            Stream = client;
            Stream.OnDisconnect += () => Dispose();
            Stream.DataReceived += (message) =>
            {
                // Read client message, and parse it into key value pairs
                string[] recieved = message.TrimStart('\\').Split('\\');
                switch (recieved[0])
                {
                    case "nicks":
                        SendNicks(ConvertToKeyValue(recieved));
                        break;
                    case "check":
                        SendCheck(ConvertToKeyValue(recieved));
                        break;
                }
            };
        }
        /// <summary>
        /// Releases the Stream's SocketAsyncEventArgs back to the pool,
        /// and free's up another slot for a new client to connect
        /// </summary>
        /// <param name="Stream">The GamespyTcpStream object that is being released.</param>
        public void Release(GamespyTcpStream Stream)
        {
            // If the stream has been released, then we stop here
            if (!IsListening || Stream.Released)
            {
                return;
            }

            // Make sure the connection is closed properly
            if (!Stream.SocketClosed)
            {
                Stream.Close();
                return;
            }

            // To prevent cross instance releasing
            if (!Object.ReferenceEquals(this, Stream.SocketManager))
            {
                throw new ArgumentException("Cannot pass a GamespyTcpStream belonging to a different TcpSocket than this one.");
            }

            // If we are still registered for this event, then the EventArgs should
            // NEVER be disposed here, or we have an error to fix
            if (Stream.DisposedEventArgs)
            {
                // Log this error
                Program.ErrorLog.Write("WARNING: [GamespyTcpSocket.Release] Event Args were disposed imporperly!");

                // Dispose old buffer tokens
                BufferManager.ReleaseBuffer(Stream.ReadEventArgs);
                BufferManager.ReleaseBuffer(Stream.WriteEventArgs);

                // Create new Read Event Args
                SocketAsyncEventArgs SockArgR = new SocketAsyncEventArgs();
                BufferManager.AssignBuffer(SockArgR);
                SocketReadWritePool.Push(SockArgR);

                // Create new Write Event Args
                SocketAsyncEventArgs SockArgW = new SocketAsyncEventArgs();
                BufferManager.AssignBuffer(SockArgW);
                SocketReadWritePool.Push(SockArgW);
            }
            else
            {
                // Set null's
                Stream.ReadEventArgs.AcceptSocket  = null;
                Stream.WriteEventArgs.AcceptSocket = null;

                // Get our ReadWrite AsyncEvent object back
                SocketReadWritePool.Push(Stream.ReadEventArgs);
                SocketReadWritePool.Push(Stream.WriteEventArgs);
            }

            // Now that we have another set of AsyncEventArgs, we can
            // release this users Semephore lock, allowing another connection
            MaxConnectionsEnforcer.Release();
        }
        /// <summary>
        /// When a new connection is established, we the parent class are responsible
        /// for handling the processing
        /// </summary>
        /// <param name="Stream">A GamespyTcpStream object that wraps the I/O AsyncEventArgs and socket</param>
        protected override void ProcessAccept(GamespyTcpStream Stream)
        {
            try
            {
                // Convert the TcpClient to a MasterClient
                GpspClient client = new GpspClient(Stream);
                Clients.TryAdd(client.ConnectionId, client);

                // Begin accepting data now that we are fully connected
                Stream.BeginReceive();
            }
            catch (Exception e)
            {
                Program.ErrorLog.Write("WARNING: An Error occured at [Gpsp.ProcessAccept] : Generating Exception Log");
                ExceptionHandler.GenerateExceptionLog(e);
                base.Release(Stream);
            }
        }
        /// <summary>
        /// Accepts a TcpClient, and begin the serverlist fetching process for the client. 
        /// This method is executed when the user updates his server browser ingame
        /// </summary>
        protected override void ProcessAccept(GamespyTcpStream Stream)
        {
            // End the operation and display the received data on
            // the console.
            try
            {
                // Convert the TcpClient to a MasterClient
                MasterClient client = new MasterClient(Stream);
                Clients.TryAdd(client.ConnectionId, client);

                // Begin accepting data now that we are fully connected
                Stream.BeginReceive();
            }
            catch (Exception e)
            {
                Program.ErrorLog.Write("WARNING: An Error occured at [MstrServer.AcceptClient] : Generating Exception Log");
                ExceptionHandler.GenerateExceptionLog(e);
                base.Release(Stream);
            }
        }
        /// <summary>
        /// Constructor
        /// </summary>
        /// <param name="client"></param>
        public MasterClient(GamespyTcpStream client)
        {
            // Internal Variables
            this.Disposed = false;

            // Generate a unique name for this connection
            this.ConnectionId = Interlocked.Increment(ref SessionsCreated);

            // Init a new client stream class
            Stream = client;
            Stream.OnDisconnect += () => Dispose();
            Stream.DataReceived += (receivedData) =>
            {
                // lets split up the message based on the delimiter
                string[] messages = receivedData.Split(new string[] { "\x00\x00\x00\x00" }, StringSplitOptions.RemoveEmptyEntries);
                foreach (string message in messages)
                {
                    // Ignore Non-BF2 related queries
                    if (message.StartsWith("battlefield2"))
                        ParseRequest(message);
                }
            };
        }
 /// <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(GamespyTcpStream Stream);
        /// <summary>
        /// Once a connection has been received, its handed off here to convert it into
        /// our client object, and prepared to be handed off to the parent for processing
        /// </summary>
        /// <param name="AcceptEventArg"></param>
        protected async void PrepareAccept(SocketAsyncEventArgs AcceptEventArg)
        {
            // If we do not get a success code here, we have a bad socket
            if (IgnoreNewConnections || AcceptEventArg.SocketError != SocketError.Success)
            {
                // This method closes the socket and releases all resources, both
                // managed and unmanaged. It internally calls Dispose.
                AcceptEventArg.AcceptSocket.Close();

                // Put the SAEA back in the pool.
                SocketAcceptPool.Push(AcceptEventArg);
                StartAcceptAsync();
                return;
            }

            // If the server is full, send an error message to the player
            if (ConnectionEnforceMode == EnforceMode.DuringPrepare)
            {
                bool Success = await MaxConnectionsEnforcer.WaitAsync(WaitTimeout);

                if (!Success)
                {
                    // If we arent even listening...
                    if (!IsListening)
                    {
                        return;
                    }

                    // Alert the client that we are full
                    if (!String.IsNullOrEmpty(FullErrorMessage))
                    {
                        byte[] buffer = Encoding.UTF8.GetBytes(
                            String.Format(@"\error\\err\0\fatal\\errmsg\{0}\id\1\final\", FullErrorMessage)
                            );
                        AcceptEventArg.AcceptSocket.Send(buffer);
                    }

                    // Log so we can track this!
                    Program.ErrorLog.Write("NOTICE: [GamespyTcpSocket.PrepareAccept] The Server is currently full! Rejecting connecting client.");

                    // Put the SAEA back in the pool.
                    AcceptEventArg.AcceptSocket.Close();
                    SocketAcceptPool.Push(AcceptEventArg);
                    StartAcceptAsync();
                    return;
                }
            }

            // Begin accepting a new connection
            StartAcceptAsync();

            // Grab a send/recieve object
            SocketAsyncEventArgs ReadArgs  = SocketReadWritePool.Pop();
            SocketAsyncEventArgs WriteArgs = SocketReadWritePool.Pop();

            // Pass over the reference to the new socket that is handling
            // this specific stream, and dereference it so we can hand the
            // acception event back over
            ReadArgs.AcceptSocket       = AcceptEventArg.AcceptSocket;
            WriteArgs.AcceptSocket      = AcceptEventArg.AcceptSocket;
            AcceptEventArg.AcceptSocket = null;

            // Hand back the AcceptEventArg so another connection can be accepted
            SocketAcceptPool.Push(AcceptEventArg);

            // Hand off processing to the parent
            GamespyTcpStream Stream = null;

            try
            {
                Stream = new GamespyTcpStream(this, ReadArgs, WriteArgs);
                ProcessAccept(Stream);
            }
            catch (Exception e)
            {
                // Report Error
                Program.ErrorLog.Write("ERROR: An Error occured at [GamespyTcpSocket.PrepareAccept] : Generating Exception Log");
                ExceptionHandler.GenerateExceptionLog(e);

                // Make sure the connection is closed properly
                if (Stream != null)
                {
                    Release(Stream);
                }
            }
        }
 /// <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(GamespyTcpStream Stream);
        /// <summary>
        /// Once a connection has been received, its handed off here to convert it into
        /// our client object, and prepared to be handed off to the parent for processing
        /// </summary>
        /// <param name="AcceptEventArg"></param>
        protected async void PrepareAccept(SocketAsyncEventArgs AcceptEventArg)
        {
            // If we do not get a success code here, we have a bad socket
            if (IgnoreNewConnections || AcceptEventArg.SocketError != SocketError.Success)
            {
                // This method closes the socket and releases all resources, both
                // managed and unmanaged. It internally calls Dispose.           
                AcceptEventArg.AcceptSocket.Close();

                // Put the SAEA back in the pool.
                SocketAcceptPool.Push(AcceptEventArg);
                StartAcceptAsync();
                return;
            }

            // If the server is full, send an error message to the player
            if (ConnectionEnforceMode == EnforceMode.DuringPrepare)
            {
                bool Success = await MaxConnectionsEnforcer.WaitAsync(WaitTimeout);
                if (!Success)
                {
                    // If we arent even listening...
                    if (!IsListening) return;

                    // Alert the client that we are full
                    if (!String.IsNullOrEmpty(FullErrorMessage))
                    {
                        byte[] buffer = Encoding.UTF8.GetBytes(
                            String.Format(@"\error\\err\0\fatal\\errmsg\{0}\id\1\final\", FullErrorMessage)
                        );
                        AcceptEventArg.AcceptSocket.Send(buffer);
                    }

                    // Log so we can track this!
                    Program.ErrorLog.Write("NOTICE: [GamespyTcpSocket.PrepareAccept] The Server is currently full! Rejecting connecting client.");

                    // Put the SAEA back in the pool.
                    AcceptEventArg.AcceptSocket.Close();
                    SocketAcceptPool.Push(AcceptEventArg);
                    StartAcceptAsync();
                    return;
                }
            }

            // Begin accepting a new connection
            StartAcceptAsync();

            // Grab a send/recieve object
            SocketAsyncEventArgs ReadArgs = SocketReadWritePool.Pop();
            SocketAsyncEventArgs WriteArgs = SocketReadWritePool.Pop();

            // Pass over the reference to the new socket that is handling
            // this specific stream, and dereference it so we can hand the
            // acception event back over
            ReadArgs.AcceptSocket = AcceptEventArg.AcceptSocket;
            WriteArgs.AcceptSocket = AcceptEventArg.AcceptSocket;
            AcceptEventArg.AcceptSocket = null;

            // Hand back the AcceptEventArg so another connection can be accepted
            SocketAcceptPool.Push(AcceptEventArg);

            // Hand off processing to the parent
            GamespyTcpStream Stream = null;
            try
            {
                Stream = new GamespyTcpStream(this, ReadArgs, WriteArgs);
                ProcessAccept(Stream);
            }
            catch (Exception e)
            {
                // Report Error
                Program.ErrorLog.Write("ERROR: An Error occured at [GamespyTcpSocket.PrepareAccept] : Generating Exception Log");
                ExceptionHandler.GenerateExceptionLog(e);

                // Make sure the connection is closed properly
                if (Stream != null)
                    Release(Stream);
            }
        }
        /// <summary>
        /// Releases the Stream's SocketAsyncEventArgs back to the pool,
        /// and free's up another slot for a new client to connect
        /// </summary>
        /// <param name="Stream">The GamespyTcpStream object that is being released.</param>
        public void Release(GamespyTcpStream Stream)
        {
            // If the stream has been released, then we stop here
            if (!IsListening || Stream.Released) return;

            // Make sure the connection is closed properly
            if (!Stream.SocketClosed)
            {
                Stream.Close();
                return;
            }

            // To prevent cross instance releasing
            if (!Object.ReferenceEquals(this, Stream.SocketManager))
                throw new ArgumentException("Cannot pass a GamespyTcpStream belonging to a different TcpSocket than this one.");

            // If we are still registered for this event, then the EventArgs should
            // NEVER be disposed here, or we have an error to fix
            if (Stream.DisposedEventArgs)
            {
                // Log this error
                Program.ErrorLog.Write("WARNING: [GamespyTcpSocket.Release] Event Args were disposed imporperly!");

                // Dispose old buffer tokens
                BufferManager.ReleaseBuffer(Stream.ReadEventArgs);
                BufferManager.ReleaseBuffer(Stream.WriteEventArgs);

                // Create new Read Event Args
                SocketAsyncEventArgs SockArgR = new SocketAsyncEventArgs();
                BufferManager.AssignBuffer(SockArgR);
                SocketReadWritePool.Push(SockArgR);

                // Create new Write Event Args
                SocketAsyncEventArgs SockArgW = new SocketAsyncEventArgs();
                BufferManager.AssignBuffer(SockArgW);
                SocketReadWritePool.Push(SockArgW);
            }
            else
            {
                // Set null's
                Stream.ReadEventArgs.AcceptSocket = null;
                Stream.WriteEventArgs.AcceptSocket = null;

                // Get our ReadWrite AsyncEvent object back
                SocketReadWritePool.Push(Stream.ReadEventArgs);
                SocketReadWritePool.Push(Stream.WriteEventArgs);
            }

            // Now that we have another set of AsyncEventArgs, we can
            // release this users Semephore lock, allowing another connection
            MaxConnectionsEnforcer.Release();
        }
Example #11
0
        /// <summary>
        /// Constructor
        /// </summary>
        public GpcmClient(GamespyTcpStream ConnectionStream, int ConnectionId)
        {
            // Set default variable values
            PlayerNick = "Connecting...";
            PlayerId = 0;
            RemoteEndPoint = (IPEndPoint)ConnectionStream.RemoteEndPoint;
            Disposed = false;
            Status = LoginStatus.None;

            // Set the connection ID
            this.ConnectionId = ConnectionId;

            // Create our Client Stream
            Stream = ConnectionStream;
            Stream.OnDisconnect += Stream_OnDisconnect;
            Stream.DataReceived += Stream_DataReceived;
            Stream.BeginReceive();
        }
Example #12
0
        /// <summary>
        /// When a new connection is established, we the parent class are responsible
        /// for handling the processing
        /// </summary>
        /// <param name="Stream">A GamespyTcpStream object that wraps the I/O AsyncEventArgs and socket</param>
        protected override void ProcessAccept(GamespyTcpStream Stream)
        {
            // Get our connection id
            int ConID = Interlocked.Increment(ref ConnectionCounter);
            GpcmClient client;

            try
            {
                // Create a new GpcmClient, passing the IO object for the TcpClientStream
                client = new GpcmClient(Stream, ConID);
                Processing.TryAdd(ConID, client);

                // Begin the asynchronous login process
                client.SendServerChallenge();
            }
            catch (Exception e)
            {
                // Log the error
                Program.ErrorLog.Write("WARNING: An Error occured at [GpcmServer.ProcessAccept] : Generating Exception Log");
                ExceptionHandler.GenerateExceptionLog(e);

                // Remove pending connection
                Processing.TryRemove(ConID, out client);

                // Release this stream so it can be used again
                base.Release(Stream);
            }
        }