示例#1
0
        /// <summary>
        /// Event called whenever raw data is received on the TCP socket.
        /// </summary>
        private void TCPPacketReceived(object sender, SocketAsyncEventArgs e)
        {
            // Parse out the actual RCON packet
            RCONPacket packet = RCONPacket.FromBytes(e.Buffer);

            if (packet.Type == PacketType.AuthResponse)
            {
                // Failed auth responses return with an ID of -1
                if (packet.Id == -1)
                {
                    throw new AuthenticationException($"Authentication failed for {_tcp.RemoteEndPoint}.");
                }

                // Tell Connect that authentication succeeded
                _authenticationTask.SetResult(true);
            }

            // Forward to handler
            RCONPacketReceived(packet);

            // Continue listening
            if (!_connected)
            {
                return;
            }
            _tcp.ReceiveAsync(e);
        }
示例#2
0
文件: RCON.cs 项目: Nerus87/CoreRcon
        /// <summary>
        /// Merges RCON packet bodies and resolves the waiting task
        /// with the full body when full response has been recived.
        /// </summary>
        /// <param name="packet"> Newly received packet </param>
        private void RCONPacketReceived(RCONPacket packet)
        {
            // Call pending result and remove from map
            TaskCompletionSource <string> taskSource;

            if (_pendingCommands.TryGetValue(packet.Id, out taskSource))
            {
                if (_multiPacket)
                {
                    //Read any previous messages
                    string body;
                    _incomingBuffer.TryGetValue(packet.Id, out body);

                    if (packet.Body == "")
                    {
                        //Avoid yielding
                        taskSource.SetResult(body ?? string.Empty);
                        _pendingCommands.Remove(packet.Id);
                        _incomingBuffer.Remove(packet.Id);
                    }
                    else
                    {
                        //Append to previous messages
                        _incomingBuffer[packet.Id] = body + packet.Body;
                    }
                }
                else
                {
                    //Avoid yielding
                    taskSource.SetResult(packet.Body);
                    _pendingCommands.Remove(packet.Id);
                }
            }
        }
示例#3
0
文件: RCON.cs 项目: Nerus87/CoreRcon
        /// <summary>
        /// Send a command to the server, and wait for the response before proceeding.  R
        /// </summary>
        /// <param name="command">Command to send to the server.</param>
        /// <exception cref = "System.AggregateException" >Connection exceptions</ exception >
        public async Task <string> SendCommandAsync(string command)
        {
            Monitor.Enter(_lock);
            // This TaskCompletion source could be initialized with TaskCreationOptions.RunContinuationsAsynchronously
            // However we this library is designed to be able to run without its own thread
            // Read more about this option here:
            // https://github.com/davidfowl/AspNetCoreDiagnosticScenarios/blob/master/AsyncGuidance.md#always-create-taskcompletionsourcet-with-taskcreationoptionsruncontinuationsasynchronously
            var source = new TaskCompletionSource <string>();

            _pendingCommands.Add(++_packetId, source);
            var packet = new RCONPacket(_packetId, PacketType.ExecCommand, command);

            Monitor.Exit(_lock);
            await SendPacketAsync(packet);

            await Task.WhenAny(source.Task, _networkConsumerTask);

            if (source.Task.IsCompleted)
            {
                return(source.Task.Result);
            }

            if (_networkConsumerTask.IsFaulted)
            {
                throw _networkConsumerTask.Exception.InnerException;
            }
            else
            {
                throw new SocketException();
            }
        }
示例#4
0
 /// <summary>
 /// Send a packet to the server.
 /// </summary>
 /// <param name="packet">Packet to send, which will be serialized.</param>
 private async Task SendPacketAsync(RCONPacket packet)
 {
     if (!_connected)
     {
         throw new InvalidOperationException("Connection is closed.");
     }
     await _tcp.SendAsync(new ArraySegment <byte>(packet.ToBytes()), SocketFlags.None);
 }
示例#5
0
        /// <summary>
        /// Attempt to parse the line, and call the callback if it succeeded.
        /// </summary>
        /// <param name="line">Single line from the server.</param>
        internal void TryCallback(RCONPacket line)
        {
            object result;

            if (TryParse(line, out result))
            {
                Callback(result);
            }
        }
示例#6
0
        /// <summary>
        /// Attempt to parse the line into an object.
        /// </summary>
        /// <param name="line">Single line from the server.</param>
        /// <param name="result">Object to parse into.</param>
        /// <returns>False if the match failed or parsing was unsuccessful.</returns>
        private bool TryParse(RCONPacket line, out object result)
        {
            if (!IsMatch(line))
            {
                result = null;
                return(false);
            }

            result = Parse(line);
            return(result != null);
        }
示例#7
0
        private void RCONPacketReceived(RCONPacket packet)
        {
            // Call pending result and remove from map
            Action <RCONPacket> action;

            if (_pendingCommands.TryGetValue(packet.Id, out action))
            {
                action?.Invoke(packet);
                _pendingCommands.Remove(packet.Id);
            }
        }
示例#8
0
        /// <summary>
        ///     Event called whenever raw data is received on the TCP socket.
        /// </summary>
        private void TCPPacketReceived(object sender, SocketAsyncEventArgs e)
        {
            // Parse out the actual RCON packet
            RCONPacket packet = null;

            try
            {
                packet = RCONPacket.FromBytes(e.Buffer);
            }
            catch (Exception exception)
            {
                Console.WriteLine("Unable to read packet, this has been observed when trying to communicate" +
                                  " with a server that is currently booting.\n" + exception.Message);
                Dispose();
                return;
            }

            if (packet.Type == PacketType.AuthResponse)
            {
                // Failed auth responses return with an ID of -1
                if (packet.Id == -1)
                {
                    Console.WriteLine($"Authentication failed for {_tcp.RemoteEndPoint}.");
                    Dispose();
                    return;
                }

                // Tell Connect that authentication succeeded

                try
                {
                    _authenticationTask.SetResult(true);
                }
                catch
                {
                    Console.WriteLine("Failure setting authentication task - disposing");
                    Dispose();
                    return;
                }
            }

            // Forward to handler
            RCONPacketReceived(packet);

            // Continue listening
            if (!_connected)
            {
                return;
            }
            _tcp.ReceiveAsync(e);
        }
示例#9
0
        /// <summary>
        /// Send a command to the server, and wait for the response before proceeding.
        /// </summary>
        /// <param name="command">Command to send to the server.</param>
        public async Task <byte[]> SendCommandAsync(byte[] command)
        {
            Monitor.Enter(_lock);
            var source = new TaskCompletionSource <RCONPacket>();

            _pendingCommands.Add(++_packetId, source.SetResult);
            var packet = new RCONPacket(_packetId, PacketType.ExecCommand, command);

            Monitor.Exit(_lock);

            await SendPacketAsync(packet);

            return((await source.Task).RawBody);
        }
示例#10
0
文件: RCON.cs 项目: Nerus87/CoreRcon
        /// <summary>
        /// Send a packet to the server.
        /// </summary>
        /// <param name="packet">Packet to send, which will be serialized.</param>
        private async Task SendPacketAsync(RCONPacket packet)
        {
            if (!_connected)
            {
                throw new InvalidOperationException("Connection is closed.");
            }
            await _tcp.SendAsync(new ArraySegment <byte>(packet.ToBytes()), SocketFlags.None);

            if (packet.Type == PacketType.ExecCommand && _multiPacket)
            {
                //Send a extra packet to find end of large packets
                await _tcp.SendAsync(new ArraySegment <byte>(new RCONPacket(packet.Id, PacketType.Response, "").ToBytes()), SocketFlags.None);
            }
        }
示例#11
0
        /// <summary>
        /// Event called whenever raw data is received on the TCP socket.
        /// </summary>
        private void TCPPacketReceived(object sender, SocketAsyncEventArgs e)
        {
            int size = BitConverter.ToInt32(e.Buffer, 0) + 4;

            if (size > e.Buffer.Length)
            {
                throw new OverflowException($"RCON message {size} bytes is larger than TCP buffer {e.Buffer.Length} bytes");
            }

            if (e.BytesTransferred + e.Offset < size)
            {
                // need more data, put e back for another go...
                e.SetBuffer(e.Offset + e.BytesTransferred, size - (e.Offset + e.BytesTransferred));

                if (!_connected)
                {
                    return;
                }
                _tcp.ReceiveAsync(e);
            }
            else
            {
                // Parse out the actual RCON packet
                RCONPacket packet = RCONPacket.FromBytes(e.Buffer);

                if (packet.Type == PacketType.AuthResponse)
                {
                    // Failed auth responses return with an ID of -1
                    if (packet.Id == -1)
                    {
                        throw new AuthenticationException($"Authentication failed for {_tcp.RemoteEndPoint}.");
                    }

                    // Tell Connect that authentication succeeded
                    _authenticationTask.SetResult(true);
                }

                // Forward to handler
                RCONPacketReceived(packet);

                // Continue listening
                if (!_connected)
                {
                    return;
                }
                e.SetBuffer(0, 4);
                _tcp.ReceiveAsync(e);
            }
        }
示例#12
0
        /// <summary>
        ///     Send a command to the server, and wait for the response before proceeding.  R
        /// </summary>
        /// <param name="command">Command to send to the server.</param>
        public async Task <string> SendCommandAsync(string command)
        {
            Monitor.Enter(_lock);
            var source = new TaskCompletionSource <string>();

            _pendingCommands.Add(++_packetId, source.SetResult);
            var packet = new RCONPacket(_packetId, PacketType.ExecCommand, command);

            Monitor.Exit(_lock);

            _staleCounter = 0;
            await SendPacketAsync(packet);

            return(await source.Task);
        }
示例#13
0
        public override SteamPacket GetReply()
        {
            if (this.ReceivePacket(1440) <= 0)
            {
                throw new RCONBanException();
            }

            int packetSize = this.bufferReader.ReadInt32() + 4;

            if (packetSize > 1440)
            {
                throw new Exception("Invalid packet size");
            }

            return(RCONPacket.CreatePacket(buffer));
        }
示例#14
0
        private void OnClientMessage(byte[] message)
        {
            // Read RCON message 
            RCONPacket packet = RCONPacket.ReadData(message);

            // Check if packet is server response (0) or invalid 
            // RCON auth response (-1)
            if (packet.ID != 0 && packet.ID != -1) return;

            switch (packet.Type)
            {
                case RCONPacketType.AUTH_RESPONSE:
                    {
                        // Read packet as AuthResponse
                        RCONAuthResponsePacket authPacket = packet as RCONAuthResponsePacket;
                        if (!authPacket.WasSuccessful())
                        {
                            OutputFunction.Invoke("Failed to connect: incorrect password.");
                            break;
                        }
                        OutputFunction.Invoke("Successfully connected!");
                        break;
                    }

                case RCONPacketType.RESPONSE_VALUE:
                    {
                        if (string.IsNullOrEmpty(packet.Body)) break;
                        OutputFunction.Invoke(packet.Body);
                        break;
                    }

                case RCONPacketType.DATA:
                    {
                        if (string.IsNullOrEmpty(packet.Body)) break;
                        OutputFunction.Invoke(packet.Body);
                        break;
                    }

                default:
                    {
                        OutputFunction.Invoke($"Received uncaught packet of type {packet.Type}");
                        break;
                    }
            }

            packet.Dispose();
        }
示例#15
0
    protected bool SyncSend(RCONPacket p)
    {
        byte[] Packets = p.OutputAsBytes();

        checked
        {
            if (S.Connected)
            {
                if (S.Send(Packets, 0, Packets.Length, SocketFlags.None) == Packets.Length)
                {
                    Thread.Sleep(1000);
                    int iCount = 0;

                    while (S.Available < 4 & iCount < 5)
                    {
                        Thread.Sleep(1000);
                        iCount++;
                    }

                    PacketsReceived = new byte[S.Available - 1 + 1];
                    int iIndex = 0;

                    while (S.Available > 0)
                    {
                        int iRec = S.Receive(PacketsReceived, iIndex, S.Available, SocketFlags.None);
                        iIndex += iRec;
                    }

                    return(iIndex > 0);
                }
            }
            else if (!S.Connected & m_connected)
            {
                m_connected = false;
            }

            return(false);
        }
    }
示例#16
0
        /// <summary>
        /// Send a command to the server, and wait for the response before proceeding.  Expect the result to be parseable into T.
        /// </summary>
        /// <typeparam name="T">Type to parse the command as.</typeparam>
        /// <param name="command">Command to send to the server.</param>
        public async Task <T> SendCommandAsync <T>(string command)
            where T : class, IParseable, new()
        {
            Monitor.Enter(_lock);
            var source   = new TaskCompletionSource <T>();
            var instance = ParserHelpers.CreateParser <T>();

            var container = new ParserContainer
            {
                IsMatch  = line => instance.IsMatch(line.Body),
                Parse    = line => instance.Parse(line.Body),
                Callback = parsed => source.SetResult((T)parsed)
            };

            _pendingCommands.Add(++_packetId, container.TryCallback);
            var packet = new RCONPacket(_packetId, PacketType.ExecCommand, command);

            Monitor.Exit(_lock);

            await SendPacketAsync(packet);

            return(await source.Task);
        }
示例#17
0
        public void Send(RCONPacket dataPacket)
        {
            byte[] byteData = dataPacket.GetBytes(true);

            this.client.Send(byteData, byteData.Length);
        }
示例#18
0
文件: RCON.cs 项目: Nerus87/CoreRcon
        /// <summary>
        /// Read data from pipeline when available, constructing new RCON packets
        /// </summary>
        /// <param name="reader"></param>
        /// <returns>Consumer Task</returns>
        async Task ReadPipeAsync(PipeReader reader)
        {
            byte[] byteArr = new byte[Constants.MAX_PACKET_SIZE];
            while (true)
            {
                ReadResult result = await reader.ReadAsync();

                ReadOnlySequence <byte> buffer      = result.Buffer;
                SequencePosition        packetStart = buffer.Start;

                if (buffer.Length < 4)
                {
                    if (result.IsCompleted)
                    {
                        break;
                    }
                    reader.AdvanceTo(packetStart, buffer.End);
                    continue;
                    // Complete header not yet received
                }
                int size = BitConverter.ToInt32(buffer.Slice(packetStart, 4).ToArray(), 0);
                if (buffer.Length >= size + 4)
                {
                    // Get packet end positions
                    SequencePosition packetEnd = buffer.GetPosition(size + 4, packetStart);
                    byteArr = buffer.Slice(packetStart, packetEnd).ToArray();
                    RCONPacket packet = RCONPacket.FromBytes(byteArr);

                    if (packet.Type == PacketType.AuthResponse)
                    {
                        // Failed auth responses return with an ID of -1
                        if (packet.Id == -1)
                        {
                            _authenticationTask.SetException(
                                new AuthenticationException($"Authentication failed for {_tcp.RemoteEndPoint}.")
                                );
                        }
                        // Tell Connect that authentication succeeded
                        _authenticationTask.SetResult(true);
                    }

                    // Forward rcon packet to handler
                    RCONPacketReceived(packet);

                    reader.AdvanceTo(packetEnd);
                }
                else
                {
                    reader.AdvanceTo(packetStart, buffer.End);
                }

                // Tell the PipeReader how much of the buffer we have consumed

                // Stop reading if there's no more data coming
                if (buffer.IsEmpty && result.IsCompleted)
                {
                    break; // exit loop
                }
            }

            // If authentication did not complete
            _authenticationTask.TrySetException(
                new AuthenticationException($"Server did not respond to auth {_tcp.RemoteEndPoint}.")
                );

            // Mark the PipeReader as complete
            await reader.CompleteAsync();
        }