diff options
| author | Fuwn <[email protected]> | 2021-03-22 17:45:35 +0000 |
|---|---|---|
| committer | Fuwn <[email protected]> | 2021-03-22 17:45:35 +0000 |
| commit | 13edb02ff4be35fa9a30e783d4a1e8bed323e0f2 (patch) | |
| tree | 628865084867c3f2c5449f7682a6e833dd998004 /src/server | |
| parent | fix: Only send to one client not all for certain commands (diff) | |
| download | whirl-13edb02ff4be35fa9a30e783d4a1e8bed323e0f2.tar.xz whirl-13edb02ff4be35fa9a30e783d4a1e8bed323e0f2.zip | |
etc: ...
Diffstat (limited to 'src/server')
| -rw-r--r-- | src/server/auto.rs | 8 | ||||
| -rw-r--r-- | src/server/auto/cmd/mod.rs | 1 | ||||
| -rw-r--r-- | src/server/auto/cmd/property.rs | 47 | ||||
| -rw-r--r-- | src/server/auto/mod.rs | 3 | ||||
| -rw-r--r-- | src/server/auto/server.rs (renamed from src/server/world.rs) | 18 | ||||
| -rw-r--r-- | src/server/auto/utils.rs | 0 | ||||
| -rw-r--r-- | src/server/world/cmd/mod.rs | 1 | ||||
| -rw-r--r-- | src/server/world/cmd/room.rs | 27 | ||||
| -rw-r--r-- | src/server/world/constants.rs | 13 | ||||
| -rw-r--r-- | src/server/world/mod.rs | 3 | ||||
| -rw-r--r-- | src/server/world/server.rs | 202 |
11 files changed, 306 insertions, 17 deletions
diff --git a/src/server/auto.rs b/src/server/auto.rs deleted file mode 100644 index 7a834b0..0000000 --- a/src/server/auto.rs +++ /dev/null @@ -1,8 +0,0 @@ -use mio::net::TcpListener; - -pub struct AutoServer; -impl AutoServer { - pub fn new(_listener: TcpListener) { - unimplemented!(); - } -}
\ No newline at end of file diff --git a/src/server/auto/cmd/mod.rs b/src/server/auto/cmd/mod.rs new file mode 100644 index 0000000..f348cd0 --- /dev/null +++ b/src/server/auto/cmd/mod.rs @@ -0,0 +1 @@ +pub mod property; diff --git a/src/server/auto/cmd/property.rs b/src/server/auto/cmd/property.rs new file mode 100644 index 0000000..b75efad --- /dev/null +++ b/src/server/auto/cmd/property.rs @@ -0,0 +1,47 @@ +pub fn create_property_update_command() -> [u8; 161] { // Vec<u8> + // let mut property = Vec::with_capacity(2); + // property.push(0x01); // ? + // property.push(0x10); // Command type + // + // // Meaningful Data + // property.push(); // Property ID + // property.push(); // Flags + // property.push(); // Access + // + // // Insert data length as first byte. + // property.insert(0, property.len() as u8 + 1); // ^ + // + // property // Return created array + + [ + 0xA1, 0xFF, 0x10, 0x08, 0x80, 0x01, 0x07, 0x31, + 0x30, 0x30, 0x30, 0x30, 0x30, 0x30, 0x1B, 0x80, + 0x01, 0x0C, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x73, + 0x33, 0x64, 0x2E, 0x63, 0x6F, 0x6D, 0x1A, 0x80, + 0x01, 0x15, 0x6D, 0x61, 0x69, 0x6C, 0x2E, 0x75, + 0x73, 0x2E, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x73, + 0x2E, 0x6E, 0x65, 0x74, 0x3A, 0x32, 0x35, 0x19, + 0x80, 0x01, 0x28, 0x68, 0x74, 0x74, 0x70, 0x3A, + 0x2F, 0x2F, 0x77, 0x77, 0x77, 0x2D, 0x64, 0x79, + 0x6E, 0x61, 0x6D, 0x69, 0x63, 0x2E, 0x75, 0x73, + 0x2E, 0x77, 0x6F, 0x72, 0x6C, 0x64, 0x73, 0x2E, + 0x6E, 0x65, 0x74, 0x2F, 0x63, 0x67, 0x69, 0x2D, + 0x62, 0x69, 0x6E, 0x18, 0x80, 0x01, 0x1F, 0x68, + 0x74, 0x74, 0x70, 0x3A, 0x2F, 0x2F, 0x77, 0x77, + 0x77, 0x2D, 0x73, 0x74, 0x61, 0x74, 0x69, 0x63, + 0x2E, 0x75, 0x73, 0x2E, 0x77, 0x6F, 0x72, 0x6C, + 0x64, 0x73, 0x2E, 0x6E, 0x65, 0x74, 0x0F, 0x80, + 0x01, 0x01, 0x33, 0x03, 0x80, 0x01, 0x02, 0x32, + 0x34, 0x01, 0x80, 0x01, 0x0C, 0x57, 0x4F, 0x52, + 0x4C, 0x44, 0x53, 0x4D, 0x41, 0x53, 0x54, 0x45, + 0x52 + ]: [u8; 161] +} + +pub fn create_property_request_command() -> [u8; 22] { + [ + 0x16, 0x01, 0x06, 0x04, 0x01, 0x30, 0x0f, 0x01, + 0x33, 0x08, 0x07, 0x31, 0x30, 0x30, 0x30, 0x30, + 0x30, 0x30, 0x03, 0x02, 0x32, 0x34 + ]: [u8; 22] +} diff --git a/src/server/auto/mod.rs b/src/server/auto/mod.rs new file mode 100644 index 0000000..7ceb58d --- /dev/null +++ b/src/server/auto/mod.rs @@ -0,0 +1,3 @@ +pub mod cmd; +pub mod server; +pub mod utils; diff --git a/src/server/world.rs b/src/server/auto/server.rs index d0a47f7..87f5e07 100644 --- a/src/server/world.rs +++ b/src/server/auto/server.rs @@ -5,17 +5,13 @@ use std::collections::HashMap; use std::str::from_utf8; use crate::cmd::buddy_list::create_buddy_list_notify_command; use crate::cmd::text::create_text_command; -use crate::cmd::property::{create_property_update_command, create_property_request_command}; +// use crate::cmd::property::{create_property_update_command, create_property_request_command}; +use crate::server::auto::cmd::property::{create_property_update_command, create_property_request_command}; use rand::Rng; use crate::server::utils::broadcast_to_all_clients; -// pub struct ClientSocket { -// tcp_stream: TcpStream, -// username: String, -// } - -pub struct WorldServer; -impl WorldServer { +pub struct AutoServer; +impl AutoServer { pub fn new(listener: TcpListener) { let poll = Poll::new().unwrap(); poll.register( @@ -59,7 +55,11 @@ impl WorldServer { } Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => break, - Err(e) => { error!("unexpected error: {}", e); break } + Err(e) => { + error!("unexpected error: {}", e); + poll.deregister(sockets.get(&Token(counter)).unwrap()).unwrap(); + break; + } } } }, diff --git a/src/server/auto/utils.rs b/src/server/auto/utils.rs new file mode 100644 index 0000000..e69de29 --- /dev/null +++ b/src/server/auto/utils.rs diff --git a/src/server/world/cmd/mod.rs b/src/server/world/cmd/mod.rs new file mode 100644 index 0000000..addf7a5 --- /dev/null +++ b/src/server/world/cmd/mod.rs @@ -0,0 +1 @@ +pub mod room; diff --git a/src/server/world/cmd/room.rs b/src/server/world/cmd/room.rs new file mode 100644 index 0000000..e41e30f --- /dev/null +++ b/src/server/world/cmd/room.rs @@ -0,0 +1,27 @@ +pub fn create_room_id_redirect_command(room_name: &str, room_id: &i32) -> Vec<u8> { + let mut room_id_redirect = Vec::new(); + // room_id_redirect.push(room_id_redirect.len() as u8 + 1); // Data length + room_id_redirect.push(0x01); // ? + room_id_redirect.push(0x1A); // Command type1 + room_id_redirect.push(room_name.len() as u8); // UTF/ room name length + for i in room_name.bytes() { room_id_redirect.push(i); } // Push `room_name` + // for i in "<dimension-1>".bytes() { room_id_redirect.push(i); } // Push room number + + // Room number + room_id_redirect.push(0x00); + room_id_redirect.push(*room_id as u8); + + // IP + room_id_redirect.push(0x00); + room_id_redirect.push(0x00); + room_id_redirect.push(0x00); + room_id_redirect.push(0x00); + + // Port + room_id_redirect.push(0x16); + room_id_redirect.push(0x29); + + room_id_redirect.insert(0, room_id_redirect.len() as u8 + 1); // Data length + + room_id_redirect +} diff --git a/src/server/world/constants.rs b/src/server/world/constants.rs new file mode 100644 index 0000000..10c9439 --- /dev/null +++ b/src/server/world/constants.rs @@ -0,0 +1,13 @@ +use std::collections::HashMap; + +pub static ROOM_IDS: phf::Map<&'static str, &'static i32> = phf::phf_map! { +"ChatElevator<dimension-1>" => &4, +"IconViewRoom1Enter<dimension-1>" => &3, +"ChatHall<dimension-1>" => &9, +"IconViewRoom1<dimension-1>" => &12, +"IconViewRoom1g<dimension-1>" => &27230, +"ReceptionView1<dimension-1>" => &6, +"ReceptionView2<dimension-1>" => &5, +"Reception<dimension-1>" => &1, +"staircase1<dimension-1>" => &11, +}; diff --git a/src/server/world/mod.rs b/src/server/world/mod.rs new file mode 100644 index 0000000..741d763 --- /dev/null +++ b/src/server/world/mod.rs @@ -0,0 +1,3 @@ +pub mod cmd; +// pub mod constants; +pub mod server; diff --git a/src/server/world/server.rs b/src/server/world/server.rs new file mode 100644 index 0000000..6aa2401 --- /dev/null +++ b/src/server/world/server.rs @@ -0,0 +1,202 @@ +use mio::net::{TcpListener, TcpStream}; +use std::io::{Read, Write}; +use mio::{Poll, Token, Ready, PollOpt, Events}; +use std::collections::HashMap; +use std::str::from_utf8; +use crate::cmd::buddy_list::create_buddy_list_notify_command; +use crate::cmd::text::create_text_command; +use crate::cmd::property::{create_property_update_command, create_property_request_command}; +use super::cmd::room::create_room_id_redirect_command; +use rand::Rng; +use crate::server::utils::broadcast_to_all_clients; +// use super::constants::ROOM_IDS; + +// pub struct ClientSocket { +// tcp_stream: TcpStream, +// username: String, +// } + +pub struct WorldServer; +impl WorldServer { + pub fn new(listener: TcpListener) { + let poll = Poll::new().unwrap(); + poll.register( + &listener, + Token(0), + Ready::readable(), + PollOpt::edge() + ).unwrap(); + + let mut counter: usize = 0; + let mut sockets: HashMap<Token, TcpStream> = HashMap::new(); + let mut requests: HashMap<Token, Vec<u8>> = HashMap::new(); + let mut buffer = [0 as u8; 1024]; + + let mut events = Events::with_capacity(1024); + loop { + poll.poll(&mut events, None).unwrap(); + for event in &events { + match event.token() { + Token(0) => { + loop { + match listener.accept() { + Ok((socket, address)) => { + counter += 1; + let token = Token(counter); + + poll.register( + &socket, + token, + Ready::readable(), + PollOpt::edge() + ).unwrap(); + + info!( + "registered ip '{}' with token '{}'", + address.ip(), token.0 + ); + + sockets.insert(token, socket); + requests.insert(token, Vec::with_capacity(192)); + } + Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => + break, + Err(e) => { + error!("unexpected error: {}", e); + poll.deregister(sockets.get(&Token(counter)).unwrap()).unwrap(); + break; + } + } + } + }, + token if event.readiness().is_readable() => { + loop { + let read = sockets.get_mut(&token).unwrap().read(&mut buffer); + match read { + Ok(0) => { sockets.remove(&token); break; } + Ok(n) => { + let req = requests.get_mut(&token).unwrap(); + for b in &buffer[0..n] { + req.push(*b); + } + + // First byte means how long data section of the packet is. + // Second byte is to be determined. + // Third byte is the request type. + + // Match packet type by descriptor; **third** byte. + match &buffer.get(2).unwrap() { // Third byte is 2 because Rust is zero-indexed. + // PROPREQ + 10 => { + info!("received property request command"); + sockets.get_mut(&token).unwrap() + .write_all(&create_property_update_command()).unwrap(); + info!("sent property update"); + } + // SESSINIT + 6 => { + info!("received session initialization command"); + sockets.get_mut(&token).unwrap() + .write_all(&create_property_request_command()).unwrap(); + info!("sent session initialization command") + } + // PROPSET + 15 => info!("received property set command"), + // BUDDYLISTUPDATE + 29 => { + info!("received buddy list update command"); + sockets.get_mut(&token).unwrap() + .write_all(&create_buddy_list_notify_command("Wirlaburla")) + .unwrap(); + info!("sent buddy notify update command"); + } + // ROOMIDRQ + 20 => { + info!("received room id request command"); + + let room_name = from_utf8( + &buffer[4..*&buffer.get(0).unwrap().to_owned() as usize] + ).unwrap(); + // let room_id = ROOM_IDS.get(&room_name[11..]).cloned().unwrap(); + // debug!("room name: {}, room id: {}", room_name, room_id); + + // Passing `0` as `room_id` parameter as currently there is + // no way to find out a room's ID based on it's name. + sockets.get_mut(&token).unwrap() + .write_all(&create_room_id_redirect_command(room_name, &0)) + .unwrap(); + info!("sent redirect id command") + } + // TEXT + 14 => { + info!("received text command"); + + // TODO: Make this into a command! + let message = from_utf8( + &buffer[6..*&buffer.get(0).unwrap().to_owned() as usize] + ).unwrap(); + info!("message: {}", message); + + // Using User as a placeholder. Ideally, this would print out the username of + // the one who sent it. + broadcast_to_all_clients( + &sockets, + &create_text_command( + // Random integer is added to the end of "User", just a development + // proof-of-concept. Since at this stage usernames aren't exactly kept, + // we can identify message senders as their connection token; `token.0`. + &format!("User{}", rand::thread_rng().gen_range(1..150).to_string()), + message + ) + ); + } + // SESSEXIT + 7 => { + info!("received session termination command"); + poll.deregister(sockets.get(&token).unwrap()).unwrap(); + info!("de-registered client: {}", token.0); + } + // Anything else, do nothing. + _ => () + } + } + Err(ref e) if e.kind() == std::io::ErrorKind::WouldBlock => + break, + Err(e) => { error!("unexpected error: {}", e); break; } + } + } + + // Unimplemented + // let ready = requests.get(&token).unwrap() + // .windows(4) + // .find(|window| is_double_crnl(*window)) + // .is_some(); + // + // if ready { + // let socket = sockets.get(&token).unwrap(); + // poll.reregister( + // socket, + // token, + // Ready::writable(), + // PollOpt::edge() | PollOpt::oneshot()).unwrap(); + // } + }, + // Unimplemented + // token if event.readiness().is_writable() => { + // println!("writeable"); + // requests.get_mut(&token).unwrap().clear(); + // sockets.get_mut(&token).unwrap().write_all("test".as_bytes()).unwrap(); + // + // // Re-use existing connection ("keep-alive") - switch back to reading + // poll.reregister( + // sockets.get(&token).unwrap(), + // token, + // Ready::readable(), + // PollOpt::edge()).unwrap(); + // }, + _ => () + } + } + } + } +} |