commit e6319b52307ec0ba2c848b335d7725d1266896ef Author: Kyle Johnsen Date: Mon Jan 17 18:16:45 2022 -0500 first commit diff --git a/.gitignore b/.gitignore new file mode 100644 index 0000000..9026c77 --- /dev/null +++ b/.gitignore @@ -0,0 +1,2 @@ +/target +.vscode diff --git a/Cargo.lock b/Cargo.lock new file mode 100644 index 0000000..4e942bf --- /dev/null +++ b/Cargo.lock @@ -0,0 +1,7 @@ +# This file is automatically @generated by Cargo. +# It is not intended for manual editing. +version = 3 + +[[package]] +name = "VelNetServerRust" +version = "0.1.0" diff --git a/Cargo.toml b/Cargo.toml new file mode 100644 index 0000000..7fb8d92 --- /dev/null +++ b/Cargo.toml @@ -0,0 +1,8 @@ +[package] +name = "VelNetServerRust" +version = "0.1.0" +edition = "2021" + +# See more keys and their definitions at https://doc.rust-lang.org/cargo/reference/manifest.html + +[dependencies] diff --git a/src/main.exe b/src/main.exe new file mode 100644 index 0000000..8943239 Binary files /dev/null and b/src/main.exe differ diff --git a/src/main.pdb b/src/main.pdb new file mode 100644 index 0000000..fd19794 Binary files /dev/null and b/src/main.pdb differ diff --git a/src/main.rs b/src/main.rs new file mode 100644 index 0000000..2951141 --- /dev/null +++ b/src/main.rs @@ -0,0 +1,213 @@ +use std::io::prelude::*; +use std::thread; +use std::net::{TcpListener, TcpStream}; +use std::collections::HashMap; +use std::sync::{Arc,Mutex}; +use std::io; +use std::sync::mpsc; +use std::sync::mpsc::{SyncSender,Receiver}; +struct Client { + logged_in: bool, + id: u32, + name: String, + room: Option, + sender: SyncSender>, + rooms_mutex: Arc>> +} + +struct Room { + clients: Mutex>> +} + +fn udp_listen(){ + println!("UDP Thread Started"); +} + +fn read_u32(stream: &mut TcpStream) -> u32 { + let mut buf:[u8;4] = [0; 4]; + stream.read_exact(&mut buf).unwrap(); + let mut size = u32::from_be_bytes(buf); + return size; +} +fn read_string(stream: &mut TcpStream) -> String { + let size = read_u32(stream); + println!("Size in bytes: {}",size); + let mut stringBytes = vec![0;size as usize]; + stream.read_exact(&mut stringBytes).unwrap(); + return String::from_utf8(stringBytes).unwrap(); +} + +fn read_login_message(stream: &mut TcpStream, client: Arc) { + println!("Got login message"); + let username = read_string(stream); + let password = read_string(stream); + + println!("Got username {} and password {}",username,password); + + let mut writeBuf = vec![]; + writeBuf.push(0u8); + writeBuf.extend_from_slice(&(client.id).to_be_bytes()); //send the client the id + + client.sender.send(writeBuf); +} + +fn read_rooms_message(stream: &mut TcpStream, client: Arc){ + +} + +fn read_join_message(stream: &mut TcpStream, client: Arc){ + let room_name = read_string(stream); + + println!("Got room message {}",room_name); + + //if the client is in a room, leave it + + if !client.room.is_none(){ + //we must leave our current room + //todo + } + + + //join that room + { + let mut rooms = client.rooms_mutex.lock().unwrap(); + if !rooms.contains_key(&room_name) { + let map: HashMap> = HashMap::new(); + let r = Room { + clients: Mutex::new(map) + }; + rooms.insert(String::from(&room_name),r); + println!("New room {} created",&room_name); + + + } + + { + let mut clients = rooms[&room_name].clients.lock().unwrap(); + clients.insert(client.id,client.clone()); + println!("Client {} joined {}",client.id,&room_name); + + //send a join message to everyone in the room + for (k,v) in clients.iter() { + let mut writeBuf = vec![]; + writeBuf.push(2u8); + writeBuf.extend_from_slice(&(client.id).to_be_bytes()); //send everyone that the client id joined the room + v.sender.send(writeBuf); + } + + //send a join message to the client for everyone else in the room (so they get a join message) + for (k,v) in clients.iter() { + if v.id != client.id { + let mut writeBuf = vec![]; + writeBuf.push(2u8); + writeBuf.extend_from_slice(&(v.id).to_be_bytes()); //send everyone that the client id joined the room + client.sender.send(writeBuf); + } + } + } + } + +} + + +fn client_read_thread(mut stream: TcpStream, client: Arc) { + let mut readBuf:[u8;1] = [0; 1]; + //messages come through as a 4-bit type identifier, that can be one of 0 (login) 1 (get rooms), 2 (join/leave room) 3(send message others) 4(send message all) 5(send message group) + loop { + + //read exactly 1 byte + stream.read_exact(&mut readBuf); + + println!("Got a message {}",readBuf[0]); + let t = readBuf[0]; + if t == 0 { + read_login_message(&mut stream, client.clone()); + } else if t == 1 { + read_rooms_message(&mut stream, client.clone()); + } else if t == 2 { + read_join_message(&mut stream, client.clone()); + } + + + } +} + +fn client_write_thread(mut stream: TcpStream, client: Arc, rx: Receiver> ) { + + //wait on messages in my queue + loop { + let m = rx.recv().unwrap(); + //write the login message out + stream.write(&m).unwrap(); + } +} + + +fn handle_client(mut stream: TcpStream, client_id: u32, clients_mutex: Arc>>>, rooms_mutex: Arc>>){ + + stream.set_nodelay(true).unwrap(); + println!("Accepted new connection"); + + let (tx, rx) = mpsc::sync_channel(10000); + //create a new client structure and add it to the list of clients + let client = Arc::new(Client{ + id: client_id, + name: String::from(""), + logged_in: false, + room: Option::None, + sender: tx, + rooms_mutex: rooms_mutex + }); + + { + let mut clients = clients_mutex.lock().unwrap(); + clients.insert(client_id, client.clone()); + } + + + let read_clone = stream.try_clone().expect("clone failed"); + let read_client = client.clone(); + let write_client = client.clone(); + let read_handle = thread::spawn(move ||{client_read_thread(read_clone, read_client)}); + let write_handle = thread::spawn(move ||{client_write_thread(stream, write_client, rx)}); + + //handle writing to the thread as needed + println!("Writing process started"); + + + + let res = read_handle.join(); + client.sender.send(vec![0]).unwrap(); + println!("Client left"); + let res = write_handle.join(); + +} + +fn tcp_listen(){ + println!("Started TCP Listener"); + let listener = TcpListener::bind("127.0.0.1:80").expect("could not bind port"); + + let clients: HashMap> = HashMap::new(); + let rooms: HashMap = HashMap::new(); + let client_mutex = Arc::new(Mutex::new(clients)); + let room_mutex = Arc::new(Mutex::new(rooms)); + let mut next_client_id = 0; + // accept connections and process them serially + for stream in listener.incoming() { + let client_mutex = Arc::clone(&client_mutex); + let room_mutex = Arc::clone(&room_mutex); + thread::spawn(move || {handle_client(stream.unwrap(), next_client_id, client_mutex, room_mutex)}); + next_client_id+=1; + } +} + +fn main() { + println!("VelNet Server Starting"); + + //start the UDP thread + let udp_handle = thread::spawn(udp_listen); + //start the TCP thread + tcp_listen(); + udp_handle.join().unwrap(); + println!("VelNet Ended"); +}