diff --git a/Cargo.toml b/Cargo.toml index 403a1e4..27a352e 100644 --- a/Cargo.toml +++ b/Cargo.toml @@ -1,8 +1,17 @@ [package] -name = "flowen" +name = "elseware" version = "0.1.0" authors = ["Jake Probst "] edition = "2018" +[[bin]] +name = "patch" +path = "src/patch/main.rs" + + [dependencies] -libpso = { path = "../libpso" } \ No newline at end of file +futures-preview = "=0.3.0-alpha.16" +libpso = { path = "../libpso" } +rand = "0.6.5" +walkdir = "2" +mio = "0.6" diff --git a/src/common/mod.rs b/src/common/mod.rs new file mode 100644 index 0000000..8aea63d --- /dev/null +++ b/src/common/mod.rs @@ -0,0 +1,72 @@ +use std::net::TcpStream; +use std::io::{Read, Write}; +use libpso::crypto::{PSOCipher, CipherError}; +use libpso::{PSOPacket, PacketParseError}; + +#[derive(Debug)] +pub enum PacketNetworkError { + CouldNotSend, + CipherError(CipherError), + PacketParseError(PacketParseError), + IOError(std::io::Error), + DataNotReady, +} + +impl From for PacketNetworkError { + fn from(err: CipherError) -> PacketNetworkError { + PacketNetworkError::CipherError(err) + } +} + +impl From for PacketNetworkError { + fn from(err: std::io::Error) -> PacketNetworkError { + PacketNetworkError::IOError(err) + } +} + +impl From for PacketNetworkError { + fn from(err: PacketParseError) -> PacketNetworkError { + PacketNetworkError::PacketParseError(err) + } +} + + + +pub fn recv_packet(socket: &mut T, cipher: &mut dyn PSOCipher) -> Result, PacketNetworkError> { + let mut size_buf = [0u8; 4]; + //socket.read_exact(&mut size_buf)?; + /*let mut offset = 0; + while offset < 4 { + offset += socket.read(&mut size_buf[offset..])?; + }*/ + let len = socket.read(&mut size_buf)?; + if len != 4 { + return Err(PacketNetworkError::DataNotReady) + } + + let mut dec_size_buf = cipher.decrypt(&size_buf.to_vec())?; + let size = u16::from_le_bytes([dec_size_buf[0], dec_size_buf[1]]); + + let mut data_buf = vec![0u8; (size - 4) as usize]; + //socket.read_exact(&mut data_buf)?; + let mut offset = 0; + while offset < size as usize - 4{ + offset += socket.read(&mut data_buf[offset..])?; + } + + let mut dec_data_buf = cipher.decrypt(&data_buf.to_vec())?; + + let mut full_buf = Vec::new(); + full_buf.append(&mut dec_size_buf); + full_buf.append(&mut dec_data_buf); + + println!("[recv]: {:X?}", full_buf); + Ok(full_buf) +} + +pub fn send_packet(socket: &mut T, cipher: &mut dyn PSOCipher, pkt: &dyn PSOPacket) -> Result<(), PacketNetworkError> { + let buf = pkt.as_bytes(); + println!("[send]: {:X?}", buf); + let cbuf = cipher.encrypt(&buf)?; + Ok(socket.write_all(&cbuf)?) +} diff --git a/src/lib.rs b/src/lib.rs new file mode 100644 index 0000000..7917840 --- /dev/null +++ b/src/lib.rs @@ -0,0 +1,4 @@ +#![feature(async_await)] + + +pub mod common; diff --git a/src/main.rs b/src/main.rs index e7a11a9..428f09d 100644 --- a/src/main.rs +++ b/src/main.rs @@ -1,3 +1,8 @@ +#![feature(async_await)] + +mod common; +//mod patch; + fn main() { - println!("Hello, world!"); + // something or other? } diff --git a/src/patch/main.rs b/src/patch/main.rs new file mode 100644 index 0000000..64ba962 --- /dev/null +++ b/src/patch/main.rs @@ -0,0 +1,246 @@ +#![allow(unused_imports)] + +use std::collections::HashMap; +use std::net::{TcpListener, SocketAddr, Ipv4Addr}; +use std::net; +use std::thread; +use std::fs; +use std::path::{Path, PathBuf, Components}; +use std::convert::AsRef; +use mio::{Events, Poll, Token, Ready, PollOpt}; +use rand::{Rng, RngCore}; +use libpso::{PacketParseError, PSOPacket}; +use libpso::patch::packet::*; +use libpso::crypto::{CipherError, PSOCipher, NullCipher}; +use libpso::crypto::pc::PSOPCCipher; +use elseware::common::{send_packet, recv_packet, PacketNetworkError}; + +const PATCH_PORT: u16 = 11000; +const DATA_PORT: u16 = 11001; + + +#[derive(Debug)] +enum PatchError { + PacketNetworkError(PacketNetworkError), + UnexpectedPacket(Box), + CloseConnection, +} + +impl From for PatchError { + fn from(err: PacketNetworkError) -> PatchError { + PatchError::PacketNetworkError(err) + } +} + +#[derive(Debug)] +pub enum PatchPacket { + PatchWelcomeReply(PatchWelcomeReply), + LoginReply(LoginReply), +} + +impl PatchPacket { + pub fn from_bytes(data: &Vec) -> Result { + match data[2] { + 0x02 => Ok(PatchPacket::PatchWelcomeReply(PatchWelcomeReply::from_bytes(data)?)), + 0x04 => Ok(PatchPacket::LoginReply(LoginReply::from_bytes(data)?)), + _ => Err(PacketParseError::WrongPacketForServerType) + } + } +} + +struct Client { + running: bool, + key_in: u32, + key_out: u32, + socket: mio::tcp::TcpStream, + cipher_in: Box, + cipher_out: Box, + patch_file_tree: PatchFileTree, + patch_file_lookup: HashMap, +} + +impl Client { + fn new(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file_lookup: HashMap) -> Client { + let mut rng = rand::thread_rng(); + let key_in: u32 = rng.gen(); + let key_out: u32 = rng.gen(); + + Client { + running: true, + key_in: key_in, + key_out: key_out, + socket: mio::tcp::TcpStream::from_stream(socket).unwrap(), + cipher_in: Box::new(NullCipher {}), + cipher_out: Box::new(NullCipher {}), + patch_file_tree: patch_file_tree, + patch_file_lookup: patch_file_lookup, + } + } + + fn send(&mut self, pkt: &dyn PSOPacket) { + match send_packet(&mut self.socket, &mut *self.cipher_out, pkt) { + Ok(_) => { + println!("[patch] send ({:?}): {:?}", self.socket, pkt); + }, + Err(err) => { + println!("[patch] error sending packet to {:?}: {:?}", self.socket, err); + self.running = false; + } + } + } + +} + +#[derive(Debug, Clone)] +enum PatchFileTree { + Directory(PathBuf, Vec), + File(PathBuf, u32), // file_id +} + +fn load_patch_dir(basedir: &str, patchbase: &str, file_ids: &mut HashMap) -> PatchFileTree { + let paths = fs::read_dir(basedir).unwrap(); + + let mut files = Vec::new(); + let mut dirs = Vec::new(); + for p in paths { + let path = p.unwrap().path(); + if path.is_dir() { + let patch_path = path.strip_prefix(basedir).unwrap(); + dirs.push(load_patch_dir(path.to_str().unwrap(), patch_path.to_str().unwrap(), file_ids)); + } + else { + let patch_path = path.strip_prefix(basedir).unwrap(); + files.push(PatchFileTree::File(patch_path.to_path_buf(), file_ids.len() as u32)); + file_ids.insert(file_ids.len() as u32, path); + } + } + + files.append(&mut dirs); + + PatchFileTree::Directory(PathBuf::from(patchbase), files) +} + +fn generate_patch_tree(basedir: &str) -> (PatchFileTree, HashMap) { + let mut file_ids = HashMap::new(); + + let patch_tree = load_patch_dir(basedir, "", &mut file_ids); + + (patch_tree, file_ids) +} + + +fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec> { + let mut pkts: Vec> = Vec::new(); + + match patch_file_tree { + PatchFileTree::Directory(dir, files) => { + pkts.push(Box::new(ChangeDirectory::new(dir.to_str().unwrap()))); + for file in files { + pkts.append(&mut get_file_list_packets(&file)); + } + pkts.push(Box::new(UpOneDirectory {})); + }, + PatchFileTree::File(path, id) => { + pkts.push(Box::new(FileInfo::new(path.to_str().unwrap(), *id))); + } + } + + pkts +} + + +// so I can not figure out why this doesnt work! +fn send_file_list(client: &mut Client) -> Result<(), PatchError> { + client.send(&PatchStartList {}); + + let pkts = get_file_list_packets(&client.patch_file_tree); + + /*for pkt in pkts { + client.send(&*pkt); + }*/ + + client.send(&ChangeDirectory::new("")); + client.send(&PatchEndList {}); + client.send(&EndIt {}); + + Ok(()) +} + + +fn handle_packet(client: &mut Client, pkt: PatchPacket) -> Result<(), PatchError> { + println!("[patch] recv({:?}): {:?}", client.socket, pkt); + + match pkt { + PatchPacket::PatchWelcomeReply(pkt) => { + client.send(&RequestLogin {}); + }, + PatchPacket::LoginReply(pkt) => { + client.send(&Message::new("hello player".to_string())); + send_file_list(client); + }, + } + + Ok(()) +} + +fn client_loop(mut client: Client) { + let poll = mio::Poll::new().unwrap(); + poll.register(&client.socket, Token(0), Ready::readable(), PollOpt::edge()); + + let mut events = Events::with_capacity(1024); + loop { + println!("about to poll {:?}", client.socket); + poll.poll(&mut events, None).unwrap(); + println!("polled!"); + + for event in &events{ + println!("event! {:?}", event); + if event.token() == Token(0) { + let pkt = recv_packet(&mut client.socket, &mut *client.cipher_in) + .and_then(|pkt| { + PatchPacket::from_bytes(&pkt) + .map_err(|err| err.into()) + }); + + match pkt { + Ok(pkt) => { + handle_packet(&mut client, pkt); + }, + Err(err) => { + println!("[patch] error recv-ing packet with {:?}: {:?}", client.socket, err); + } + } + } + } + } +} + +fn new_client(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file_lookup: HashMap) { + let mut client = Client::new(socket, patch_file_tree, patch_file_lookup); + let welcome_pkt = PatchWelcome::new(client.key_out, client.key_in); + client.send(&welcome_pkt); + client.cipher_in = Box::new(PSOPCCipher::new(client.key_in)); + client.cipher_out = Box::new(PSOPCCipher::new(client.key_out)); + client_loop(client); +} + + +fn main() { + println!("[patch] starting server"); + + let listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), PATCH_PORT))).unwrap(); + + let (patch_file_tree, patch_file_lookup) = generate_patch_tree("patchfiles/"); + + while let Ok((socket, addr)) = listener.accept() { + let local_patch_file_tree = patch_file_tree.clone(); + let local_patch_file_lookup = patch_file_lookup.clone(); + thread::spawn(move || { + println!("[patch] accepted connection: {}", addr); + new_client(socket, local_patch_file_tree, local_patch_file_lookup); + }); + } + + + println!("[patch] exiting..."); +} diff --git a/src/patch/patchserver.rs b/src/patch/patchserver.rs new file mode 100644 index 0000000..4210887 --- /dev/null +++ b/src/patch/patchserver.rs @@ -0,0 +1,154 @@ +use std::net::{TcpListener, TcpStream, SocketAddr, Ipv4Addr}; +use std::thread; +use elseware::common::{send_packet, recv_packet, PacketNetworkError}; +use rand::{Rng, RngCore}; +use libpso::{PacketParseError, PSOPacket}; +use libpso::patch::packet::*; +use libpso::crypto::{CipherError, PSOCipher, NullCipher}; +use libpso::crypto::pc::PSOPCCipher; + +const PATCH_PORT: u16 = 11000; + + +#[derive(Debug)] +enum PatchError { + PacketNetworkError(PacketNetworkError) +} + +impl From for PatchError { + fn from(err: PacketNetworkError) -> PatchError { + PatchError::PacketNetworkError(err) + } +} + +#[derive(Debug)] +pub enum PatchPacket { + PatchWelcomeReply(PatchWelcomeReply), + StartFilePatching(StartFilePatching), +} + + +struct Client { + running: bool, + key_in: u32, + key_out: u32, + socket: TcpStream, + cipher_in: Box, + cipher_out: Box, +} + + +impl Client { + fn new(socket: TcpStream) -> Client { + let mut rng = rand::thread_rng(); + let key_in: u32 = rng.gen(); + let key_out: u32 = rng.gen(); + + Client { + running: true, + key_in: key_in, + key_out: key_out, + socket: socket, + cipher_in: Box::new(NullCipher {}), + cipher_out: Box::new(NullCipher {}), + //cipher_in: Box::new(PSOPCCipher::new(key_in)), + //cipher_out: Box::new(PSOPCCipher::new(key_out)), + } + } + + fn send(&mut self, pkt: &PSOPacket) { + match send_packet(&mut self.socket, &mut *self.cipher_out, pkt) { + Ok(_) => { + println!("[patch] send ({:?}): {:?}", self.socket, pkt); + }, + Err(err) => { + println!("[patch] error sending packet to {:?}: {:?}", self.socket, err); + self.running = false; + } + } + } + + fn handle_packet(&mut self, patch_pkt: &PatchPacket) -> Result<(), PatchError> { + println!("[patch] recv({:?}): {:?}", self.socket, patch_pkt); + + match patch_pkt { + PatchPacket::PatchWelcomeReply(pkt) => { + }, + PatchPacket::StartFilePatching(pkt) => { + }, + } + + Ok(()) + } + + fn run(mut self) { + let welcome_pkt = PatchWelcome::new(self.key_out, self.key_in); + self.send(&welcome_pkt); + self.cipher_in = Box::new(PSOPCCipher::new(self.key_in)); + self.cipher_out = Box::new(PSOPCCipher::new(self.key_out)); + + while self.running { + let res = recv_packet(&mut self.socket, &mut *self.cipher_in) + .and_then(|pkt| { + PatchPacket::from_bytes(&pkt) + .map_err(|err| err.into()) + }) + .map(|pkt| { + self.handle_packet(&pkt) + }); + + println!("res! {:?}", res); + match res { + Ok(_) => {}, + Err(err) => { + println!("[patch] error handling packet with {:?}: {:?}", self.socket, err); + self.running = false; + } + } + + /*.or_else(|err| { + println!("[patch] error handling packet with {:?}: {:?}", self.socket, err); + self.running = false; + })?;*/ + } + } +} + +impl PatchPacket { + pub fn from_bytes(data: &Vec) -> Result { + match data[2] { + 0x02 => Ok(PatchPacket::PatchWelcomeReply(PatchWelcomeReply::from_bytes(data)?)), + 0x04 => Ok(PatchPacket::StartFilePatching(StartFilePatching::from_bytes(data)?)), + _ => Err(PacketParseError::WrongPacketForServerType) + } + } +} + + +fn handle_client(socket: TcpStream) { + let client = Client::new(socket); + client.run(); +} + +pub fn patch_server_loop() { + println!("[patch] starting server"); + let listener = TcpListener::bind(&SocketAddr::from((Ipv4Addr::new(0,0,0,0), PATCH_PORT))).unwrap(); + + + loop { + match listener.accept() { + Ok((socket, addr)) => { + println!("[patch] accepted connection: {}", addr); + thread::spawn(move || { + handle_client(socket); + }); + } + Err(e) => { + println!("[patch] accepted connection error {:?}", e); + } + } + } + + + +}