summaryrefslogtreecommitdiffstats
path: root/src/bin/client/connection.rs
diff options
context:
space:
mode:
authorsalmonik <salmonik@tuta.io>2026-08-24 14:48:12 +0200
committersalmonik <salmonik@tuta.io>2026-08-24 14:48:12 +0200
commit5d6b5049c2a34a3f8abe725d4a871ba84a0dd714 (patch)
tree57cb03bf59b3358a96742f455d38c21f4f645396 /src/bin/client/connection.rs
parentstable and working, both platforms (diff)
downloadzagan-bet-5d6b5049c2a34a3f8abe725d4a871ba84a0dd714.tar.gz
zagan-bet-5d6b5049c2a34a3f8abe725d4a871ba84a0dd714.zip
TLS transport and games framework on client and server
Diffstat (limited to '')
-rw-r--r--src/bin/client/connection.rs136
1 files changed, 115 insertions, 21 deletions
diff --git a/src/bin/client/connection.rs b/src/bin/client/connection.rs
index b07bf01..c5d506d 100644
--- a/src/bin/client/connection.rs
+++ b/src/bin/client/connection.rs
@@ -1,46 +1,76 @@
1use std::io::{BufRead, BufReader, Write}; 1use crate::database;
2use native_tls::TlsConnector;
3use rusqlite::Connection;
4use std::io::{Read, Write};
2use std::net::TcpStream; 5use std::net::TcpStream;
3use std::sync::mpsc; 6use std::sync::mpsc;
7use std::sync::Arc;
8use std::sync::Mutex;
4use std::thread; 9use std::thread;
5use std::time::{Duration, Instant}; 10use std::time::{Duration, Instant};
6use rusqlite::Connection;
7use crate::database;
8 11
9pub fn connect(addr: &str, conn: &Connection) -> Result<(TcpStream, Option<String>), Box<dyn std::error::Error>> { 12static UNSAFE_MODE: Mutex<bool> = Mutex::new(false);
13
14pub fn set_unsafe_mode(unsafe_mode: bool) {
15 let mut mode = UNSAFE_MODE.lock().unwrap();
16 *mode = unsafe_mode;
17}
18
19pub fn connect(
20 addr: &str,
21 conn: &Connection,
22) -> Result<(TlsStream, Option<String>), Box<dyn std::error::Error>> {
10 let (tx, rx) = mpsc::channel(); 23 let (tx, rx) = mpsc::channel();
11 let addr_str = addr.to_string(); 24 let addr_str = addr.to_string();
12 thread::spawn(move || { 25 let server_name = addr_str
13 match TcpStream::connect(&addr_str) { 26 .split(':')
14 Ok(s) => tx.send(Ok(s)).unwrap(), 27 .next()
15 Err(e) => tx.send(Err(e)).unwrap(), 28 .unwrap_or("127.0.0.1")
16 } 29 .to_string();
30 thread::spawn(move || match TcpStream::connect(&addr_str) {
31 Ok(s) => tx.send(Ok(s)).unwrap(),
32 Err(e) => tx.send(Err(e)).unwrap(),
17 }); 33 });
18 match rx.recv_timeout(Duration::from_secs(3)) { 34 match rx.recv_timeout(Duration::from_secs(3)) {
19 Ok(Ok(s)) => { 35 Ok(Ok(s)) => {
20 let mut ping_writer = s.try_clone().unwrap(); 36 let unsafe_mode = *UNSAFE_MODE.lock().unwrap();
21 let mut ping_reader = BufReader::new(s.try_clone().unwrap()); 37
38 let connector = if unsafe_mode {
39 TlsConnector::builder()
40 .danger_accept_invalid_certs(true)
41 .danger_accept_invalid_hostnames(true)
42 .build()?
43 } else {
44 TlsConnector::builder().build()?
45 };
46
47 let tls_stream = connector.connect(&server_name, s)?;
48 let mut tls = TlsStream::new(tls_stream);
49
22 let start = Instant::now(); 50 let start = Instant::now();
23 writeln!(ping_writer, "PING").unwrap(); 51 tls.write_line("PING")?;
24 let mut response = String::new(); 52 let mut response = String::new();
25 ping_reader.read_line(&mut response).unwrap(); 53 tls.read_line(&mut response)?;
26 let elapsed = start.elapsed(); 54 let elapsed = start.elapsed();
27 println!("\n\rConnected to {} with ping delay: {:?}", addr, elapsed); 55 println!(
28 56 "\n\rConnected to {} with ping delay: {:?} (TLS)",
29 // Check for credentials and auto-auth 57 addr, elapsed
58 );
59
30 if let Some((username, password)) = database::get_credentials(conn, addr) { 60 if let Some((username, password)) = database::get_credentials(conn, addr) {
31 let auth_msg = format!("AUTH {} {}", username, password); 61 let auth_msg = format!("AUTH {} {}", username, password);
32 writeln!(ping_writer, "{}", auth_msg).unwrap(); 62 tls.write_line(&auth_msg)?;
33 let mut auth_response = String::new(); 63 let mut auth_response = String::new();
34 ping_reader.read_line(&mut auth_response).unwrap(); 64 tls.read_line(&mut auth_response)?;
35 if auth_response.trim().starts_with("OK") { 65 if auth_response.trim().starts_with("OK") {
36 println!("Authenticated as {}", username); 66 println!("Authenticated as {}", username);
37 Ok((s, Some(username))) 67 Ok((tls, Some(username)))
38 } else { 68 } else {
39 println!("Authentication failed: {}", auth_response.trim()); 69 println!("Authentication failed: {}", auth_response.trim());
40 Ok((s, None)) 70 Ok((tls, None))
41 } 71 }
42 } else { 72 } else {
43 Ok((s, None)) 73 Ok((tls, None))
44 } 74 }
45 } 75 }
46 Ok(Err(e)) => Err(Box::new(e)), 76 Ok(Err(e)) => Err(Box::new(e)),
@@ -48,3 +78,67 @@ pub fn connect(addr: &str, conn: &Connection) -> Result<(TcpStream, Option<Strin
48 Err(_) => Err("Connection attempt failed".into()), 78 Err(_) => Err("Connection attempt failed".into()),
49 } 79 }
50} 80}
81
82pub struct TlsStream {
83 stream: Arc<Mutex<native_tls::TlsStream<TcpStream>>>,
84}
85
86unsafe impl Send for TlsStream {}
87unsafe impl Sync for TlsStream {}
88
89impl TlsStream {
90 pub fn new(stream: native_tls::TlsStream<TcpStream>) -> Self {
91 Self {
92 stream: Arc::new(Mutex::new(stream)),
93 }
94 }
95
96 pub fn read_line(&mut self, buf: &mut String) -> std::io::Result<usize> {
97 let mut byte_buf = [0u8; 1024];
98 let mut stream = self.stream.lock().unwrap();
99 loop {
100 let n = stream.read(&mut byte_buf)?;
101 if n == 0 {
102 return Ok(0);
103 }
104 let chunk = std::str::from_utf8(&byte_buf[..n]).unwrap_or("");
105 buf.push_str(chunk);
106 if buf.contains('\n') {
107 return Ok(n);
108 }
109 }
110 }
111
112 pub fn write_line(&mut self, msg: &str) -> std::io::Result<()> {
113 let mut stream = self.stream.lock().unwrap();
114 stream.write_all(msg.as_bytes())?;
115 stream.write_all(b"\n")?;
116 stream.flush()?;
117 Ok(())
118 }
119
120 pub fn try_clone(&self) -> std::io::Result<TlsStream> {
121 Ok(TlsStream {
122 stream: Arc::clone(&self.stream),
123 })
124 }
125}
126
127impl Read for TlsStream {
128 fn read(&mut self, buf: &mut [u8]) -> std::io::Result<usize> {
129 let mut stream = self.stream.lock().unwrap();
130 stream.read(buf)
131 }
132}
133
134impl Write for TlsStream {
135 fn write(&mut self, buf: &[u8]) -> std::io::Result<usize> {
136 let mut stream = self.stream.lock().unwrap();
137 stream.write(buf)
138 }
139
140 fn flush(&mut self) -> std::io::Result<()> {
141 let mut stream = self.stream.lock().unwrap();
142 stream.flush()
143 }
144}