1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
use std::net::{SocketAddr, TcpStream};
use std::time::Duration;
use crate::error::RconError;
use crate::error::RconError::{CommandTooLongError, DesynchronizedPacketError, PasswordIncorrectError, UnexpectedPacketError};
use crate::packet::{Packet, TYPE_AUTH, TYPE_AUTH_RESPONSE, TYPE_EXEC, TYPE_RESPONSE};
pub struct SingleConnection {
stream: TcpStream,
counter: i32,
}
impl SingleConnection {
pub fn open<S: Into<String>>(address: S, pass: S, connect_timeout: Option<Duration>) -> Result<Self, RconError> {
let socket_address: SocketAddr = address.into().parse()?;
let mut stream = match connect_timeout {
Some(timeout) => TcpStream::connect_timeout(&socket_address, timeout),
None => TcpStream::connect(&socket_address),
}?;
Packet::new(0, TYPE_AUTH, pass.into()).send_internal(&mut stream)?;
let response = Packet::read(&mut stream)?;
if *response.get_packet_type() != TYPE_AUTH_RESPONSE {
return Err(UnexpectedPacketError);
}
if *response.get_id() == -1 {
return Err(PasswordIncorrectError);
}
Ok(Self {
stream,
counter: 0,
})
}
pub fn exec<S: Into<String>>(&mut self, cmd: S) -> Result<String, RconError> {
let cmd = cmd.into();
if cmd.len() > 1014 {
return Err(CommandTooLongError);
}
let mut end_id = -1;
let mut result = String::new();
let original_id = self.next_counter();
Packet::new(original_id, TYPE_EXEC, cmd).send_internal(&mut self.stream)?;
loop {
let response = Packet::read(&mut self.stream)?;
if end_id == -1 {
end_id = self.next_counter();
Packet::new(end_id, TYPE_EXEC, "").send_internal(&mut self.stream)?;
}
if *response.get_id() != original_id && *response.get_id() != end_id {
return Err(DesynchronizedPacketError);
}
if *response.get_packet_type() != TYPE_RESPONSE {
return Err(UnexpectedPacketError);
}
if *response.get_id() == end_id {
break;
}
result += response.get_body().as_str();
}
Ok(result)
}
fn next_counter(&mut self) -> i32 {
self.counter = match self.counter.checked_add(1) {
Some(new) => new,
None => 1,
};
self.counter
}
}