gui/network/
tcp_client.rs1use crate::network::connection_state::{ConnectionState, SessionState};
9use common::logging::LogLevel::{Error, Info, SuccessEvent};
10use common::networking::messages::{
11 HandshakeRequest, HandshakeResponse, TcpClientMessage, TcpServerMessage,
12};
13use common::{networking, r_log};
14use std::env;
15use std::io::{Read, Write};
16use std::net::{Shutdown, TcpStream};
17use std::sync::atomic::{AtomicBool, Ordering};
18use std::sync::mpsc::{Receiver, Sender};
19use std::sync::Arc;
20use std::thread;
21use crate::controller::{send_ui_event, UiEvent};
22
23pub(crate) struct TcpClient {
28 target: String,
29 tcp_receiver: Receiver<TcpClientMessage>,
30 tcp_sender: Sender<TcpServerMessage>,
31}
32
33impl TcpClient {
34 pub(crate) fn new(
41 target: String,
42 tcp_receiver: Receiver<TcpClientMessage>,
43 tcp_sender: Sender<TcpServerMessage>,
44 ) -> Self {
45 Self {
46 target,
47 tcp_receiver,
48 tcp_sender,
49 }
50 }
51
52 fn set_connection_state(state: ConnectionState) {
59 if let Some(sender) = crate::UI_EVENT_SENDER.read().unwrap().as_ref() {
60 let _ = sender.send(UiEvent::SetConnectionState { state });
61 }
62 }
63
64 pub(crate) fn start_tcp_client(&mut self) {
71 r_log!(
72 Info,
73 "Trying to establish connection to {} ...",
74 self.target
75 );
76
77 let mut write_stream = match TcpStream::connect(&self.target) {
78 Ok(stream) => stream,
79 Err(e) => {
80 eprintln!("[System] Unable to connect to {}: {}", self.target, e);
81 return;
82 }
83 };
84
85 let client_version = env!("CARGO_PKG_VERSION");
86 let protocol_hash = networking::messages::get_protocol_version();
87
88 let req = HandshakeRequest {
89 magic_string: "REKTAL".into(),
90 protocol_hash,
91 client_version: client_version.into(),
92 };
93
94 Self::set_connection_state(ConnectionState::ConnectionPending);
95
96 match bincode::serialize(&req) {
97 Ok(payload) => {
98 let len = payload.len() as u32;
99 if let Err(e) = write_stream.write_all(&len.to_be_bytes()) {
100 r_log!(Error, "Got error while sending length prefix: {}", e);
101 return;
102 }
103 if let Err(e) = write_stream.write_all(&payload) {
104 r_log!(Error, "Got error while sending HandshakeRequest: {}", e);
105 return;
106 }
107 }
108 Err(e) => {
109 r_log!(Error, "Got error while serializing HandshakeRequest: {}", e);
110 return;
111 }
112 }
113
114 let mut len_buf = [0u8; 4];
116 if let Err(e) = write_stream.read_exact(&mut len_buf) {
117 r_log!(Error, "Error reading HandshakeResponse length: {}", e);
118 Self::set_connection_state(ConnectionState::Error);
119 return;
120 }
121 let msg_len = u32::from_be_bytes(len_buf) as usize;
122 let mut response_buffer = vec![0u8; msg_len];
123 if let Err(e) = write_stream.read_exact(&mut response_buffer) {
124 r_log!(Error, "Error reading HandshakeResponse body: {}", e);
125 Self::set_connection_state(ConnectionState::Error);
126 return;
127 }
128
129 let res = match bincode::deserialize::<HandshakeResponse>(&response_buffer) {
130 Ok(res) => res,
131 Err(e) => {
132 r_log!(Error, "Error deserializing HandshakeResponse: {}", e);
133 return;
134 }
135 };
136
137 match res {
138 HandshakeResponse::Ok => {
139 r_log!(SuccessEvent, "Version {} verified!", client_version);
140 Self::set_connection_state(ConnectionState::Connected {
141 session_state: SessionState::LoggedOut,
142 });
143 }
144 HandshakeResponse::Mismatch { server_version } => {
145 r_log!(
146 Error,
147 "Version mismatch! this client has the version {}. Kernel has the version {}",
148 client_version,
149 server_version
150 );
151 Self::set_connection_state(ConnectionState::Error);
152 return;
153 }
154 }
155
156 let read_stream = match write_stream.try_clone() {
157 Ok(stream) => stream,
158 Err(e) => {
159 r_log!(Error, "Failed to clone TcpStream: {}", e);
160 return;
161 }
162 };
163
164 let tcp_sender = self.tcp_sender.clone();
165 let is_disconnecting = Arc::new(AtomicBool::new(false));
166 let is_disconnecting_clone = Arc::clone(&is_disconnecting);
167
168 thread::spawn(move || {
169 Self::listen_tcp(read_stream, tcp_sender, is_disconnecting_clone);
170 });
171
172 Self::write_thread(self, write_stream, is_disconnecting);
173 }
174
175 fn listen_tcp(
181 mut read_stream: TcpStream,
182 tcp_sender: Sender<TcpServerMessage>,
183 is_disconnecting: Arc<AtomicBool>,
184 ) {
185 loop {
186 let mut len_buf = [0u8; 4];
187 let mut response_buffer = match read_stream.read_exact(&mut len_buf) {
188 Ok(_) => {
189 let msg_len = u32::from_be_bytes(len_buf) as usize;
190 vec![0u8; msg_len]
191 }
192 Err(e) => {
193 if is_disconnecting.load(Ordering::SeqCst) {
194 r_log!(Info, "TCP connection closed (requested by client).");
195 } else {
196 r_log!(Error, "TCP connection lost unexpectedly from server: {}", e);
197 Self::set_connection_state(ConnectionState::Error);
198 }
199 break;
200 }
201 };
202
203 match read_stream.read_exact(&mut response_buffer) {
204 Ok(_) => match bincode::deserialize::<TcpServerMessage>(&response_buffer) {
205 Ok(kernel_msg) => {
206 if let Err(e) = tcp_sender.send(kernel_msg) {
207 if is_disconnecting.load(Ordering::SeqCst) {
208 r_log!(Info, "TCP receiver channel closed, stopping listen thread.");
209 } else {
210 r_log!(Error, "Error sending TcpServerMessage: {}", e);
211 }
212 break;
213 }
214 }
215 Err(e) => {
216 r_log!(Error, "Error deserializing TcpServerMessage: {}", e);
217 }
218 },
219 Err(e) => {
220 if is_disconnecting.load(Ordering::SeqCst) {
221 r_log!(Info, "TCP connection closed while reading body.");
222 } else {
223 r_log!(Error, "Error reading from TcpStream: {}", e);
224 Self::set_connection_state(ConnectionState::Error);
225 }
226 break;
227 }
228 }
229 }
230 }
231
232 fn write_thread(&self, mut write_stream: TcpStream, is_disconnecting: Arc<AtomicBool>) {
237 while let Ok(message) = self.tcp_receiver.recv() {
238 match bincode::serialize(&message) {
239 Ok(payload) => {
240 let len = payload.len() as u32;
241 if let Err(e) = write_stream.write_all(&len.to_be_bytes()) {
242 r_log!(
243 Error,
244 "Got error while sending length prefix: {} Stopped write-Thread",
245 e
246 );
247 break;
248 }
249 if let Err(e) = write_stream.write_all(&payload) {
250 r_log!(
251 Error,
252 "Got error while sending to Server: {} Stopped write-Thread",
253 e
254 );
255 break;
256 }
257 }
258 Err(e) => {
259 r_log!(Error, "Got error while serializing response: {}", e);
260 break;
261 }
262 }
263 }
264 is_disconnecting.store(true, Ordering::SeqCst);
265 Self::close_tcp_connection(&write_stream);
266 }
267
268 fn close_tcp_connection(stream: &TcpStream) {
273 if let Err(e) = stream.shutdown(Shutdown::Both) {
274 r_log!(Error, "Failed to shutdown TcpStream: {}", e);
275 }
276 send_ui_event(UiEvent::SetConnectionState {
277 state: ConnectionState::Disconnected,
278 });
279 }
280}