예제 #1
0
        /// <summary>
        /// Releases the SocketAsyncEventArgs back to the pool,
        /// and free's up another slot for a new client to connect
        /// </summary>
        /// <param name="Stream"></param>
        protected void Release(SocketAsyncEventArgs e)
        {
            // Get our ReadWrite AsyncEvent object back
            SocketReadWritePool.Push(e);

            // Now that we have another set of AsyncEventArgs, we can
            // release this users Semephore lock, allowing another connection
            MaxConnectionsEnforcer.Release();
        }
예제 #2
0
        /// <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)
            {
                // 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();
        }
예제 #3
0
        public GamespyTcpSocket(IPEndPoint bindTo, int MaxConnections)
        {
            // Create our Socket
            Listener = new Socket(AddressFamily.InterNetwork, SocketType.Stream, ProtocolType.Tcp);

            // Set Socket options
            Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.DontLinger, true);
            Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.Linger, false);
            Listener.SetSocketOption(SocketOptionLevel.Socket, SocketOptionName.KeepAlive, true);

            // Bind to our port
            Listener.Bind(bindTo);
            Listener.Listen(25);

            // Set the rest of our internals
            MaxNumConnections      = MaxConnections;
            MaxConnectionsEnforcer = new SemaphoreSlim(MaxNumConnections, MaxNumConnections);
            SocketAcceptPool       = new SocketAsyncEventArgsPool(ConcurrentAcceptPoolSize);
            SocketReadWritePool    = new SocketAsyncEventArgsPool(MaxNumConnections * 2);

            // Create our Buffer Manager for IO operations.
            // Always allocate double space, one for recieving, and another for sending
            BufferManager = new BufferManager(MaxNumConnections * 2, BufferSizePerOperation);

            // Assign our Connection Accept SocketAsyncEventArgs object instances
            for (int i = 0; i < ConcurrentAcceptPoolSize; i++)
            {
                SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs();
                SockArg.Completed += (s, e) => PrepareAccept(e);

                // Do NOT assign buffer space for Accept operations!
                SocketAcceptPool.Push(SockArg);
            }

            // Assign our Connection IO SocketAsyncEventArgs object instances
            for (int i = 0; i < MaxNumConnections * 2; i++)
            {
                SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs();
                BufferManager.AssignBuffer(SockArg);
                SocketReadWritePool.Push(SockArg);
            }

            // set public internals
            IsListening = true;
        }
예제 #4
0
        public GamespyUdpSocket(IPEndPoint bindTo, int MaxConnections)
        {
            // Create our Socket
            this.Port = Port;
            Listener  = new Socket(AddressFamily.InterNetwork, SocketType.Dgram, ProtocolType.Udp)
            {
                SendTimeout       = 5000, // We have a limited pool, so we dont want to be locked often
                SendBufferSize    = BufferSizePerEvent,
                ReceiveBufferSize = BufferSizePerEvent
            };

            // Bind to our port
            Listener.Bind(bindTo);

            // Set the rest of our internals
            MaxNumConnections      = MaxConnections;
            MaxConnectionsEnforcer = new SemaphoreSlim(MaxNumConnections, MaxNumConnections);
            SocketReadWritePool    = new SocketAsyncEventArgsPool(MaxNumConnections);

            // Create our Buffer Manager for IO operations.
            BufferManager = new BufferManager(
                MaxNumConnections,
                BufferSizePerEvent
                );

            // Assign our Connection IO SocketAsyncEventArgs object instances
            for (int i = 0; i < MaxNumConnections; i++)
            {
                SocketAsyncEventArgs SockArg = new SocketAsyncEventArgs();
                SockArg.Completed += IOComplete;
                BufferManager.AssignBuffer(SockArg);
                SocketReadWritePool.Push(SockArg);
            }

            // set public internals
            IsRunning  = true;
            IsDisposed = false;
        }
예제 #5
0
        /// <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       = 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
                OnException(e);

                // Make sure the connection is closed properly
                if (Stream != null)
                {
                    Release(Stream);
                }
            }
        }