Jake Probst
5 years ago
6 changed files with 493 additions and 3 deletions
-
13Cargo.toml
-
72src/common/mod.rs
-
4src/lib.rs
-
7src/main.rs
-
246src/patch/main.rs
-
154src/patch/patchserver.rs
@ -1,8 +1,17 @@ |
|||||
[package] |
[package] |
||||
name = "flowen" |
|
||||
|
name = "elseware" |
||||
version = "0.1.0" |
version = "0.1.0" |
||||
authors = ["Jake Probst <jake.probst@gmail.com>"] |
authors = ["Jake Probst <jake.probst@gmail.com>"] |
||||
edition = "2018" |
edition = "2018" |
||||
|
|
||||
|
[[bin]] |
||||
|
name = "patch" |
||||
|
path = "src/patch/main.rs" |
||||
|
|
||||
|
|
||||
[dependencies] |
[dependencies] |
||||
libpso = { path = "../libpso" } |
|
||||
|
futures-preview = "=0.3.0-alpha.16" |
||||
|
libpso = { path = "../libpso" } |
||||
|
rand = "0.6.5" |
||||
|
walkdir = "2" |
||||
|
mio = "0.6" |
@ -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)?)
|
||||
|
}
|
@ -0,0 +1,4 @@ |
|||||
|
#![feature(async_await)]
|
||||
|
|
||||
|
|
||||
|
pub mod common;
|
@ -1,3 +1,8 @@ |
|||||
|
#![feature(async_await)]
|
||||
|
|
||||
|
mod common;
|
||||
|
//mod patch;
|
||||
|
|
||||
fn main() {
|
fn main() {
|
||||
println!("Hello, world!");
|
|
||||
|
// something or other?
|
||||
}
|
}
|
@ -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...");
|
||||
|
}
|
@ -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);
|
||||
|
}
|
||||
|
}
|
||||
|
}
|
||||
|
|
||||
|
|
||||
|
|
||||
|
}
|
Write
Preview
Loading…
Cancel
Save
Reference in new issue