You can not select more than 25 topics Topics must start with a letter or number, can include dashes ('-') and can be up to 35 characters long.

432 lines
14 KiB

  1. use std::collections::{HashMap, HashSet};
  2. use std::fs;
  3. use std::io;
  4. use std::io::{Read};
  5. use std::path::{Path, PathBuf};
  6. use rand::Rng;
  7. use crc::{crc32, Hasher32};
  8. use libpso::{PacketParseError, PSOPacket};
  9. use libpso::packet::patch::*;
  10. use libpso::crypto::pc::PSOPCCipher;
  11. use ron::de::from_str;
  12. use serde::Deserialize;
  13. use networking::mainloop::{NetworkError};
  14. use networking::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId};
  15. #[derive(Debug)]
  16. pub enum PatchError {
  17. NetworkError(NetworkError),
  18. IOError(std::io::Error),
  19. }
  20. impl From<NetworkError> for PatchError {
  21. fn from(err: NetworkError) -> PatchError {
  22. PatchError::NetworkError(err)
  23. }
  24. }
  25. impl From<std::io::Error> for PatchError {
  26. fn from(err: std::io::Error) -> PatchError {
  27. PatchError::IOError(err)
  28. }
  29. }
  30. #[derive(Debug, Clone)]
  31. pub struct PatchFile {
  32. path: PathBuf,
  33. checksum: u32,
  34. size: u32,
  35. }
  36. pub enum PatchTreeIterItem {
  37. Directory(PathBuf),
  38. File(PathBuf, u32),
  39. UpDirectory,
  40. }
  41. #[derive(Debug, Clone)]
  42. pub enum PatchFileTree {
  43. Directory(PathBuf, Vec<PatchFileTree>),
  44. File(PathBuf, u32), // file_id
  45. }
  46. impl PatchFileTree {
  47. fn iter_dir(tree: &PatchFileTree) -> Vec<PatchTreeIterItem> {
  48. let mut v = Vec::new();
  49. match tree {
  50. PatchFileTree::Directory(dir, files) => {
  51. v.push(PatchTreeIterItem::Directory(dir.clone()));
  52. for file in files {
  53. v.append(&mut PatchFileTree::iter_dir(file));
  54. }
  55. v.push(PatchTreeIterItem::UpDirectory);
  56. },
  57. PatchFileTree::File(path, id) => {
  58. v.push(PatchTreeIterItem::File(path.clone(), *id));
  59. }
  60. }
  61. v
  62. }
  63. pub fn flatten(&self) -> Vec<PatchTreeIterItem> {
  64. PatchFileTree::iter_dir(self)
  65. }
  66. }
  67. #[derive(Debug)]
  68. pub enum RecvPatchPacket {
  69. PatchWelcomeReply(PatchWelcomeReply),
  70. LoginReply(LoginReply),
  71. FileInfoReply(FileInfoReply),
  72. FileInfoListEnd(FileInfoListEnd),
  73. }
  74. impl RecvServerPacket for RecvPatchPacket {
  75. fn from_bytes(data: &[u8]) -> Result<RecvPatchPacket, PacketParseError> {
  76. match data[2] {
  77. 0x02 => Ok(RecvPatchPacket::PatchWelcomeReply(PatchWelcomeReply::from_bytes(data)?)),
  78. 0x04 => Ok(RecvPatchPacket::LoginReply(LoginReply::from_bytes(data)?)),
  79. 0x0F => Ok(RecvPatchPacket::FileInfoReply(FileInfoReply::from_bytes(data)?)),
  80. 0x10 => Ok(RecvPatchPacket::FileInfoListEnd(FileInfoListEnd::from_bytes(data)?)),
  81. _ => Err(PacketParseError::WrongPacketForServerType(u16::from_le_bytes([data[2], data[3]]), data.to_vec()))
  82. }
  83. }
  84. }
  85. #[derive(Debug)]
  86. pub enum SendPatchPacket {
  87. ChangeDirectory(ChangeDirectory),
  88. EndFileSend(EndFileSend),
  89. FileInfo(FileInfo),
  90. FileSend(Box<FileSend>),
  91. FilesToPatchMetadata(FilesToPatchMetadata),
  92. FinalizePatching(FinalizePatching),
  93. Message(Message),
  94. PatchEndList(PatchEndList),
  95. PatchStartList(PatchStartList),
  96. PatchWelcome(PatchWelcome),
  97. RequestLogin(RequestLogin),
  98. StartFileSend(StartFileSend),
  99. UpOneDirectory(UpOneDirectory),
  100. }
  101. impl SendServerPacket for SendPatchPacket {
  102. fn as_bytes(&self) -> Vec<u8> {
  103. match self {
  104. SendPatchPacket::ChangeDirectory(pkt) => pkt.as_bytes(),
  105. SendPatchPacket::EndFileSend(pkt) => pkt.as_bytes(),
  106. SendPatchPacket::FileInfo(pkt) => pkt.as_bytes(),
  107. SendPatchPacket::FileSend(pkt) => pkt.as_bytes(),
  108. SendPatchPacket::FilesToPatchMetadata(pkt) => pkt.as_bytes(),
  109. SendPatchPacket::FinalizePatching(pkt) => pkt.as_bytes(),
  110. SendPatchPacket::Message(pkt) => pkt.as_bytes(),
  111. SendPatchPacket::PatchEndList(pkt) => pkt.as_bytes(),
  112. SendPatchPacket::PatchStartList(pkt) => pkt.as_bytes(),
  113. SendPatchPacket::PatchWelcome(pkt) => pkt.as_bytes(),
  114. SendPatchPacket::RequestLogin(pkt) => pkt.as_bytes(),
  115. SendPatchPacket::StartFileSend(pkt) => pkt.as_bytes(),
  116. SendPatchPacket::UpOneDirectory(pkt) => pkt.as_bytes(),
  117. }
  118. }
  119. }
  120. #[derive(Clone)]
  121. pub struct PatchServerState {
  122. patch_file_tree: PatchFileTree,
  123. patch_file_lookup: HashMap<u32, PatchFile>,
  124. patch_file_info: Vec<FileInfoReply>,
  125. patch_motd: String,
  126. }
  127. impl PatchServerState {
  128. pub fn new(patch_file_tree: PatchFileTree, patch_file_lookup: HashMap<u32, PatchFile>, patch_motd: String) -> PatchServerState {
  129. PatchServerState {
  130. patch_file_tree,
  131. patch_file_lookup,
  132. patch_file_info: Vec::new(),
  133. patch_motd,
  134. }
  135. }
  136. }
  137. #[async_trait::async_trait]
  138. impl ServerState for PatchServerState {
  139. type SendPacket = SendPatchPacket;
  140. type RecvPacket = RecvPatchPacket;
  141. type Cipher = PSOPCCipher;
  142. type PacketError = PatchError;
  143. async fn on_connect(&mut self, _id: ClientId) -> Result<Vec<OnConnect<Self::SendPacket, Self::Cipher>>, PatchError> {
  144. let mut rng = rand::thread_rng();
  145. let key_in: u32 = rng.gen();
  146. let key_out: u32 = rng.gen();
  147. Ok(vec![OnConnect::Packet(SendPatchPacket::PatchWelcome(PatchWelcome::new(key_out, key_in))),
  148. OnConnect::Cipher(PSOPCCipher::new(key_in), PSOPCCipher::new(key_out))
  149. ])
  150. }
  151. async fn handle(&mut self, id: ClientId, pkt: RecvPatchPacket) -> Result<Vec<(ClientId, SendPatchPacket)>, PatchError> {
  152. Ok(match pkt {
  153. RecvPatchPacket::PatchWelcomeReply(_pkt) => {
  154. vec![SendPatchPacket::RequestLogin(RequestLogin {})]
  155. .into_iter()
  156. .map(move |pkt| (id, pkt))
  157. .collect()
  158. },
  159. RecvPatchPacket::LoginReply(_pkt) => {
  160. let mut pkts = vec![SendPatchPacket::Message(Message::new(self.patch_motd.clone()))];
  161. pkts.append(&mut get_file_list_packets(&self.patch_file_tree));
  162. pkts.push(SendPatchPacket::PatchEndList(PatchEndList {}));
  163. pkts
  164. .into_iter()
  165. .map(move |pkt| (id, pkt))
  166. .collect()
  167. },
  168. RecvPatchPacket::FileInfoReply(pkt) => {
  169. self.patch_file_info.push(pkt);
  170. Vec::new()
  171. },
  172. RecvPatchPacket::FileInfoListEnd(_pkt) => {
  173. let need_update = self.patch_file_info.iter()
  174. .filter(|file_info| does_file_need_updating(file_info, &self.patch_file_lookup))
  175. .collect::<Vec<_>>();
  176. let total_size = need_update.iter().fold(0, |a, file_info| a + file_info.size);
  177. let total_files = need_update.len() as u32;
  178. vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)),
  179. SendPatchPacket::PatchStartList(PatchStartList {})]
  180. .into_iter()
  181. .chain(SendFileIterator::new(self))
  182. .map(move |pkt| (id, pkt))
  183. .collect()
  184. }
  185. })
  186. }
  187. async fn on_disconnect(&mut self, _id: ClientId) -> Result<Vec<(ClientId, SendPatchPacket)>, PatchError> {
  188. Ok(Vec::new())
  189. }
  190. }
  191. fn load_patch_dir(basedir: &str, patchbase: &str, file_ids: &mut HashMap<u32, PatchFile>) -> PatchFileTree {
  192. let paths = fs::read_dir(basedir).expect("could not read directory");
  193. let mut files = Vec::new();
  194. let mut dirs = Vec::new();
  195. for p in paths {
  196. let path = p.expect("not a real path").path();
  197. let patch_path = path.strip_prefix(basedir).unwrap();
  198. if path.is_dir() {
  199. dirs.push(load_patch_dir(path.to_str().unwrap(), patch_path.to_str().unwrap(), file_ids));
  200. }
  201. else {
  202. files.push(PatchFileTree::File(patch_path.to_path_buf(), file_ids.len() as u32));
  203. let (checksum, size) = get_checksum_and_size(&path).unwrap();
  204. file_ids.insert(file_ids.len() as u32, PatchFile {
  205. path,
  206. checksum,
  207. size,
  208. });
  209. }
  210. }
  211. files.append(&mut dirs);
  212. PatchFileTree::Directory(PathBuf::from(patchbase), files)
  213. }
  214. pub fn generate_patch_tree(basedir: &str) -> (PatchFileTree, HashMap<u32, PatchFile>) {
  215. let mut file_ids = HashMap::new();
  216. let patch_tree = load_patch_dir(basedir, "", &mut file_ids);
  217. (patch_tree, file_ids)
  218. }
  219. fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec<SendPatchPacket> {
  220. let mut pkts = Vec::new();
  221. for item in patch_file_tree.flatten() {
  222. match item {
  223. PatchTreeIterItem::Directory(path) => {
  224. pkts.push(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap())));
  225. },
  226. PatchTreeIterItem::File(path, id) => {
  227. pkts.push(SendPatchPacket::FileInfo(FileInfo::new(path.to_str().unwrap(), id)));
  228. },
  229. PatchTreeIterItem::UpDirectory => {
  230. pkts.push(SendPatchPacket::UpOneDirectory(UpOneDirectory {}));
  231. }
  232. }
  233. }
  234. pkts
  235. }
  236. fn get_checksum_and_size(path: &Path) -> Result<(u32, u32), PatchError> {
  237. let file = fs::File::open(path)?;
  238. let size = file.metadata().unwrap().len();
  239. let mut crc = crc32::Digest::new(crc32::IEEE);
  240. let mut buf = [0u8; 1024 * 32];
  241. let mut reader = io::BufReader::new(file);
  242. while let Ok(len) = reader.read(&mut buf) {
  243. if len == 0 {
  244. break;
  245. }
  246. crc.write(&buf[0..len]);
  247. }
  248. Ok((crc.sum32(), size as u32))
  249. }
  250. fn does_file_need_updating(file_info: &FileInfoReply, patch_file_lookup: &HashMap<u32, PatchFile>) -> bool {
  251. let patch_file = patch_file_lookup.get(&file_info.id).unwrap();
  252. patch_file.checksum != file_info.checksum || patch_file.size != file_info.size
  253. }
  254. struct SendFileIterator {
  255. done: bool,
  256. file_iter: Box<dyn Iterator<Item = PatchTreeIterItem> + Send>,
  257. patch_file_lookup: HashMap<u32, PatchFile>,
  258. current_file: Option<io::BufReader<fs::File>>,
  259. chunk_num: u32,
  260. }
  261. impl SendFileIterator {
  262. fn new(state: &PatchServerState) -> SendFileIterator {
  263. let file_ids_to_update = state.patch_file_info.iter()
  264. .filter(|file_info| does_file_need_updating(file_info, &state.patch_file_lookup))
  265. .map(|k| k.id)
  266. .collect::<HashSet<_>>();
  267. SendFileIterator {
  268. done: false,
  269. patch_file_lookup: state.patch_file_lookup.clone(),
  270. file_iter: Box::new(state.patch_file_tree.flatten().into_iter().filter(move |file| {
  271. match file {
  272. PatchTreeIterItem::File(_path, id) => {
  273. file_ids_to_update.contains(id)
  274. },
  275. _ => true,
  276. }
  277. })),
  278. current_file: None,
  279. chunk_num: 0,
  280. }
  281. }
  282. }
  283. impl Iterator for SendFileIterator {
  284. type Item = SendPatchPacket;
  285. fn next(&mut self) -> Option<Self::Item> {
  286. if self.done {
  287. return None;
  288. }
  289. match self.current_file {
  290. Some(ref mut file) => {
  291. let mut buf = [0u8; PATCH_FILE_CHUNK_SIZE as usize];
  292. let len = file.read(&mut buf).unwrap();
  293. if len == 0 {
  294. self.current_file = None;
  295. self.chunk_num = 0;
  296. Some(SendPatchPacket::EndFileSend(EndFileSend::new()))
  297. }
  298. else {
  299. let mut crc = crc32::Digest::new(crc32::IEEE);
  300. crc.write(&buf[0..len]);
  301. let pkt = SendPatchPacket::FileSend(Box::new(FileSend {
  302. chunk_num: self.chunk_num,
  303. checksum: crc.sum32(),
  304. chunk_size: len as u32,
  305. buffer: buf,
  306. }));
  307. self.chunk_num += 1;
  308. Some(pkt)
  309. }
  310. },
  311. None => {
  312. match self.file_iter.next() {
  313. Some(next_file) => {
  314. match next_file {
  315. PatchTreeIterItem::Directory(path) => {
  316. Some(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap())))
  317. },
  318. PatchTreeIterItem::File(path, id) => {
  319. let patch_file = self.patch_file_lookup.get(&id).unwrap();
  320. let file = fs::File::open(&patch_file.path).unwrap();
  321. let size = file.metadata().unwrap().len();
  322. self.current_file = Some(io::BufReader::new(file));
  323. Some(SendPatchPacket::StartFileSend(StartFileSend::new(path.to_str().unwrap(), size as u32, id)))
  324. },
  325. PatchTreeIterItem::UpDirectory => {
  326. Some(SendPatchPacket::UpOneDirectory(UpOneDirectory {}))
  327. },
  328. }
  329. },
  330. None => {
  331. self.current_file = None;
  332. self.done = true;
  333. Some(SendPatchPacket::FinalizePatching(FinalizePatching {}))
  334. }
  335. }
  336. }
  337. }
  338. }
  339. }
  340. #[derive(Debug, Deserialize)]
  341. pub struct PatchConfig {
  342. pub path: String,
  343. pub ip: String, // TODO: this does nothing
  344. pub port: u16,
  345. }
  346. pub fn load_config() -> PatchConfig {
  347. let ini_file = match fs::File::open(std::path::Path::new("patch.ron")) {
  348. Err(err) => panic!("Failed to open patch.ron config file. \n{err}"),
  349. Ok(ini_file) => ini_file,
  350. };
  351. let mut s = String::new();
  352. if let Err(err) = (&ini_file).read_to_string(&mut s) {
  353. panic!("Failed to read patch.ron config file. \n{err}");
  354. }
  355. let config: PatchConfig = match from_str(s.as_str()) {
  356. Ok(config) => config,
  357. Err(err) => panic!("Failed to load values from patch.ron \n{err}"),
  358. };
  359. config
  360. }
  361. pub fn load_config_env() -> PatchConfig {
  362. let patch_path = std::env::var("PATCHFILE_DIR").unwrap();
  363. let patch_port = std::env::var("PATCH_PORT").unwrap().parse().unwrap();
  364. PatchConfig {
  365. path: patch_path,
  366. ip: "127.0.0.1".into(),
  367. port: patch_port,
  368. }
  369. }
  370. pub fn load_motd() -> String {
  371. if let Ok(m) = fs::read_to_string("patch.motd") {
  372. m
  373. }
  374. else {
  375. "Welcome to Elseware!".to_string()
  376. }
  377. }