Beispiel #1
0
        /// <summary>
        /// Send the proper authentication packet and parse the response
        /// </summary>
        /// <param name="password">Current server password</param>
        /// <returns>True if the connection has been authenticated; False elsewhere</returns>
        /// <remarks>This method must be called prior to sending any other command</remarks>
        /// <exception cref="ArgumentException">Is thrown if <paramref name="password"/> parameter is null or empty</exception>
        public async Task <bool> AuthenticateAsync(string password)
        {
            if (string.IsNullOrEmpty(password))
            {
                throw new ArgumentException("password parameter must be a non null non empty string");
            }

            var authPacket = new RconPacket(PacketType.Auth, password);
            var response   = await _socket.SendDataAndReadResponseAsync(authPacket.GetBytes());

            var responsePacket = RconPacket.FromBytes(response);

            return(responsePacket.Id != -1);
        }
Beispiel #2
0
        /// <summary>
        /// Send a message encapsulated into an Rcon packet and get the response
        /// </summary>
        /// <param name="packet">Packet to be sent</param>
        /// <returns>The response to this command</returns>
        private async Task <string> SendPacketAsync(RconPacket packet, bool isMultiPacketResponse = false)
        {
            var packetDescription = new Operation(packet, isMultiPacketResponse);

            operations.Enqueue(packetDescription);
            await channel.SendAsync(packet.ToBytes());

            if (isMultiPacketResponse)
            {
                await channel.SendAsync(RconPacket.Dummy.Value.ToBytes());
            }

            return(await packetDescription.TaskCompletionSource.Task);
        }
Beispiel #3
0
        /// <summary>
        /// Create a new RconPacket from a byte array
        /// </summary>
        /// <param name="buffer">Input buffer</param>
        /// <returns>Parsed RconPacket</returns>
        /// <exception cref="System.ArgumentException">When buffer is null or its size is less than 14</exception>
        public static RconPacket FromBytes(byte[] buffer)
        {
            if (buffer == null || buffer.Length < 14)
            {
                throw new ArgumentException("Invalid packet");
            }
            RconPacket packet = new RconPacket()
            {
                Body = Encoding.UTF8.GetString(buffer, bodyIndex, buffer.ToInt32(sizeIndex) - 10),
                Id   = buffer.ToInt32(idIndex)
            };

            return(packet);
        }
Beispiel #4
0
        /// <summary>
        /// Send a command encapsulated into an Rcon message packet and get the response
        /// </summary>
        /// <param name="command">Command to be executed</param>
        /// <returns>The response to this command</returns>
        /// <exception cref="ArgumentException">Is thrown if <paramref name="command"/> parameter is null or empty</exception>
        /// <exception cref="InvalidOperationException">Is thrown if the connection is not properly opened and authenticated</exception>
        public async Task <string> ExecuteCommandAsync(string command)
        {
            if (string.IsNullOrEmpty(command))
            {
                throw new ArgumentException("command parameter must be a non null non empty string");
            }

            if (!_socket.IsConnected)
            {
                throw new InvalidOperationException("You must authenticate the connection before sending any command to the server");
            }

            var commandPacket = new RconPacket(PacketType.ExecCommand, command);
            var response      = await _socket.SendDataAndReadResponseAsync(commandPacket.GetBytes());

            var responsePacket = RconPacket.FromBytes(response);

            return(responsePacket.Body);
        }
Beispiel #5
0
        /// <summary>
        /// Send the proper authentication packet and parse the response
        /// </summary>
        /// <param name="password">Current server password</param>
        /// <returns>True if the connection has been authenticated; False elsewhere</returns>
        /// <remarks>This method must be called prior to sending any other command</remarks>
        /// <exception cref="ArgumentException">Is thrown if <paramref name="password"/> parameter is null or empty</exception>
        public async Task <bool> AuthenticateAsync(string password)
        {
            if (string.IsNullOrEmpty(password))
            {
                throw new ArgumentException("password parameter must be a non null non empty string");
            }

            var authPacket = RconPacket.Create(PacketType.Auth, password);

            try
            {
                var response = await SendPacketAsync(authPacket);
            }
            catch (AuthenticationException ex)
            {
                return(false);
            }
            return(true);
        }
Beispiel #6
0
 public void Add(RconPacket packet) => PacketsBuffer.Add(packet);
Beispiel #7
0
 public Operation(RconPacket originalRequest, bool isMultiPacketResponse)
 {
     OriginalRequest       = originalRequest;
     TaskCompletionSource  = new TaskCompletionSource <string>(TaskCreationOptions.RunContinuationsAsynchronously);
     IsMultiPacketResponse = isMultiPacketResponse;
 }
Beispiel #8
0
 public Task <string> ExecuteCommandAsync(string command, bool isMultiPacketResponse = false)
 {
     return(SendPacketAsync(RconPacket.Create(PacketType.ExecCommand, command), isMultiPacketResponse));
 }
Beispiel #9
0
        private async Task ReadFromPipeAsync(PipeReader reader)
        {
            while (true)
            {
                var readResult = await reader.ReadAsync();

                var buffer        = readResult.Buffer;
                var startPosition = buffer.Start;
                if (buffer.Length < 4)                 // not enough bytes to get the packet length, need to read more
                {
                    if (readResult.IsCompleted)
                    {
                        break;
                    }

                    reader.AdvanceTo(startPosition, buffer.End);
                    continue;
                }

                var packetSize = BitConverter.ToInt32(buffer.Slice(startPosition, 4).ToArray());
                if (buffer.Length >= packetSize + 4)
                {
                    var endPosition = buffer.GetPosition(packetSize + 4, startPosition);
                    var rconPacket  = RconPacket.FromBytes(buffer.Slice(startPosition, endPosition).ToArray());
                    if (!rconPacket.IsDummy)
                    {
                        var currentOperation = operations.Peek();
                        currentOperation.Add(rconPacket);
                        if (currentOperation.OriginalRequest.Type == PacketType.Auth && rconPacket.Type == PacketType.Response)
                        {
                            // According to RCON documentation an empty RESPONSE packet must be sent after the auth request, but at the moment only CS:GO does so ..
                        }
                        else if (currentOperation.IsMultiPacketResponse && !string.IsNullOrEmpty(rconPacket.Body))
                        {
                            // Accumulate and move on
                        }
                        else
                        {
                            operations.Dequeue();
                            if (rconPacket.Id == -1)
                            {
                                currentOperation.TaskCompletionSource.SetException(new AuthenticationException("Invalid password"));
                            }
                            else
                            {
                                currentOperation.TaskCompletionSource.SetResult(currentOperation.Body);
                            }
                        }
                    }

                    reader.AdvanceTo(endPosition);
                }
                else
                {
                    reader.AdvanceTo(startPosition, buffer.End);
                }

                if (buffer.IsEmpty && readResult.IsCompleted)
                {
                    break;
                }
            }

            await reader.CompleteAsync();
        }