base patch server
This commit is contained in:
		
							parent
							
								
									bfc65cedea
								
							
						
					
					
						commit
						28fa89266a
					
				
							
								
								
									
										13
									
								
								Cargo.toml
									
									
									
									
									
								
							
							
						
						
									
										13
									
								
								Cargo.toml
									
									
									
									
									
								
							| @ -1,8 +1,17 @@ | ||||
| [package] | ||||
| name = "flowen" | ||||
| name = "elseware" | ||||
| version = "0.1.0" | ||||
| authors = ["Jake Probst <jake.probst@gmail.com>"] | ||||
| edition = "2018" | ||||
| 
 | ||||
| [[bin]] | ||||
| name = "patch" | ||||
| path = "src/patch/main.rs" | ||||
| 
 | ||||
| 
 | ||||
| [dependencies] | ||||
| libpso = { path = "../libpso" } | ||||
| futures-preview = "=0.3.0-alpha.16" | ||||
| libpso = { path = "../libpso" } | ||||
| rand = "0.6.5" | ||||
| walkdir = "2" | ||||
| mio = "0.6" | ||||
|  | ||||
							
								
								
									
										72
									
								
								src/common/mod.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										72
									
								
								src/common/mod.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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<CipherError> for PacketNetworkError { | ||||
|     fn from(err: CipherError) -> PacketNetworkError { | ||||
|         PacketNetworkError::CipherError(err) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<std::io::Error> for PacketNetworkError { | ||||
|     fn from(err: std::io::Error) -> PacketNetworkError { | ||||
|         PacketNetworkError::IOError(err) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| impl From<PacketParseError> for PacketNetworkError { | ||||
|     fn from(err: PacketParseError) -> PacketNetworkError { | ||||
|         PacketNetworkError::PacketParseError(err) | ||||
|     } | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 
 | ||||
| pub fn recv_packet<T: Read>(socket: &mut T, cipher: &mut dyn PSOCipher) -> Result<Vec<u8>, 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<T: Write>(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)?) | ||||
| } | ||||
							
								
								
									
										4
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										4
									
								
								src/lib.rs
									
									
									
									
									
										Normal file
									
								
							| @ -0,0 +1,4 @@ | ||||
| #![feature(async_await)] | ||||
| 
 | ||||
| 
 | ||||
| pub mod common; | ||||
| @ -1,3 +1,8 @@ | ||||
| #![feature(async_await)] | ||||
| 
 | ||||
| mod common; | ||||
| //mod patch;
 | ||||
| 
 | ||||
| fn main() { | ||||
|     println!("Hello, world!"); | ||||
|     // something or other?
 | ||||
| } | ||||
|  | ||||
							
								
								
									
										246
									
								
								src/patch/main.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										246
									
								
								src/patch/main.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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<dyn PSOPacket>), | ||||
|     CloseConnection, | ||||
| } | ||||
| 
 | ||||
| impl From<PacketNetworkError> 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<u8>) -> Result<PatchPacket, PacketParseError> { | ||||
|         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<dyn PSOCipher>, | ||||
|     cipher_out: Box<dyn PSOCipher>, | ||||
|     patch_file_tree: PatchFileTree, | ||||
|     patch_file_lookup: HashMap<u32, PathBuf>, | ||||
| } | ||||
| 
 | ||||
| impl Client { | ||||
|     fn new(socket: net::TcpStream, patch_file_tree: PatchFileTree, patch_file_lookup: HashMap<u32, PathBuf>) -> 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<PatchFileTree>), | ||||
|     File(PathBuf, u32), // file_id
 | ||||
| } | ||||
| 
 | ||||
| fn load_patch_dir(basedir: &str, patchbase: &str, file_ids: &mut HashMap<u32, PathBuf>) -> 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<u32, PathBuf>) { | ||||
|     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<Box<dyn PSOPacket>> { | ||||
|     let mut pkts: Vec<Box<dyn PSOPacket>> = 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<u32, PathBuf>) { | ||||
|     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..."); | ||||
| } | ||||
							
								
								
									
										154
									
								
								src/patch/patchserver.rs
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										154
									
								
								src/patch/patchserver.rs
									
									
									
									
									
										Normal file
									
								
							| @ -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<PacketNetworkError> 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<PSOCipher>, | ||||
|     cipher_out: Box<PSOCipher>, | ||||
| } | ||||
| 
 | ||||
| 
 | ||||
| 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<u8>) -> Result<PatchPacket, PacketParseError> { | ||||
|         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); | ||||
|             } | ||||
|         } | ||||
|     } | ||||
| 
 | ||||
| 
 | ||||
|     
 | ||||
| } | ||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user