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.

397 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::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 crate::common::network::{PacketNetworkError};
  14. use crate::common::serverstate::{RecvServerPacket, SendServerPacket, ServerState, OnConnect, ClientId};
  15. #[derive(Debug)]
  16. pub enum PatchError {
  17. PacketNetworkError(PacketNetworkError),
  18. IOError(std::io::Error),
  19. }
  20. impl From<PacketNetworkError> for PatchError {
  21. fn from(err: PacketNetworkError) -> PatchError {
  22. PatchError::PacketNetworkError(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(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. pub struct PatchServerState {
  121. patch_file_tree: PatchFileTree,
  122. patch_file_lookup: HashMap<u32, PatchFile>,
  123. patch_file_info: Vec<FileInfoReply>,
  124. }
  125. impl PatchServerState {
  126. pub fn new(patch_file_tree: PatchFileTree, patch_file_lookup: HashMap<u32, PatchFile>) -> PatchServerState {
  127. PatchServerState {
  128. patch_file_tree: patch_file_tree,
  129. patch_file_lookup: patch_file_lookup,
  130. patch_file_info: Vec::new(),
  131. }
  132. }
  133. }
  134. impl ServerState for PatchServerState {
  135. type SendPacket = SendPatchPacket;
  136. type RecvPacket = RecvPatchPacket;
  137. type PacketError = PatchError;
  138. fn on_connect(&mut self, _id: ClientId) -> Vec<OnConnect<Self::SendPacket>> {
  139. let mut rng = rand::thread_rng();
  140. let key_in: u32 = rng.gen();
  141. let key_out: u32 = rng.gen();
  142. vec![OnConnect::Packet(SendPatchPacket::PatchWelcome(PatchWelcome::new(key_out, key_in))),
  143. OnConnect::Cipher((Box::new(PSOPCCipher::new(key_in)), Box::new(PSOPCCipher::new(key_out))))
  144. ]
  145. }
  146. fn handle(&mut self, id: ClientId, pkt: &RecvPatchPacket)
  147. -> Result<Box<dyn Iterator<Item = (ClientId, SendPatchPacket)>>, PatchError> {
  148. Ok(match pkt {
  149. RecvPatchPacket::PatchWelcomeReply(_pkt) => {
  150. Box::new(vec![SendPatchPacket::RequestLogin(RequestLogin {})].into_iter().map(move |pkt| (id, pkt)))
  151. },
  152. RecvPatchPacket::LoginReply(_pkt) => {
  153. let mut p = vec![SendPatchPacket::Message(Message::new("hello player".to_string()))];
  154. p.append(&mut get_file_list_packets(&self.patch_file_tree));
  155. p.push(SendPatchPacket::PatchEndList(PatchEndList {}));
  156. Box::new(p.into_iter().map(move |pkt| (id, pkt)))
  157. },
  158. RecvPatchPacket::FileInfoReply(pkt) => {
  159. self.patch_file_info.push(pkt.clone());
  160. Box::new(None.into_iter().map(move |pkt| (id, pkt)))
  161. },
  162. RecvPatchPacket::FileInfoListEnd(_pkt) => {
  163. let need_update = self.patch_file_info.iter()
  164. .filter(|file_info| does_file_need_updating(file_info, &self.patch_file_lookup))
  165. .collect::<Vec<_>>();
  166. let total_size = need_update.iter().fold(0, |a, file_info| a + file_info.size);
  167. let total_files = need_update.len() as u32;
  168. let p = vec![SendPatchPacket::FilesToPatchMetadata(FilesToPatchMetadata::new(total_size, total_files)),
  169. SendPatchPacket::PatchStartList(PatchStartList {})
  170. ];
  171. Box::new(p.into_iter().chain(SendFileIterator::new(&self)).map(move |pkt| (id, pkt)))
  172. }
  173. })
  174. }
  175. }
  176. fn load_patch_dir(basedir: &str, patchbase: &str, file_ids: &mut HashMap<u32, PatchFile>) -> PatchFileTree {
  177. let paths = fs::read_dir(basedir).expect("could not read directory");
  178. let mut files = Vec::new();
  179. let mut dirs = Vec::new();
  180. for p in paths {
  181. let path = p.expect("not a real path").path();
  182. if path.is_dir() {
  183. let patch_path = path.strip_prefix(basedir).unwrap();
  184. dirs.push(load_patch_dir(path.to_str().unwrap(), patch_path.to_str().unwrap(), file_ids));
  185. }
  186. else {
  187. let patch_path = path.strip_prefix(basedir).unwrap();
  188. files.push(PatchFileTree::File(patch_path.to_path_buf(), file_ids.len() as u32));
  189. let (checksum, size) = get_checksum_and_size(&path).unwrap();
  190. file_ids.insert(file_ids.len() as u32, PatchFile {
  191. path: path,
  192. checksum: checksum,
  193. size: size,
  194. });
  195. }
  196. }
  197. files.append(&mut dirs);
  198. PatchFileTree::Directory(PathBuf::from(patchbase), files)
  199. }
  200. pub fn generate_patch_tree(basedir: &str) -> (PatchFileTree, HashMap<u32, PatchFile>) {
  201. let mut file_ids = HashMap::new();
  202. let patch_tree = load_patch_dir(basedir, "", &mut file_ids);
  203. (patch_tree, file_ids)
  204. }
  205. fn get_file_list_packets(patch_file_tree: &PatchFileTree) -> Vec<SendPatchPacket> {
  206. let mut pkts = Vec::new();
  207. for item in patch_file_tree.flatten() {
  208. match item {
  209. PatchTreeIterItem::Directory(path) => {
  210. pkts.push(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap())));
  211. },
  212. PatchTreeIterItem::File(path, id) => {
  213. pkts.push(SendPatchPacket::FileInfo(FileInfo::new(path.to_str().unwrap(), id)));
  214. },
  215. PatchTreeIterItem::UpDirectory => {
  216. pkts.push(SendPatchPacket::UpOneDirectory(UpOneDirectory {}));
  217. }
  218. }
  219. }
  220. pkts
  221. }
  222. fn get_checksum_and_size(path: &PathBuf) -> Result<(u32, u32), PatchError> {
  223. let file = fs::File::open(path)?;
  224. let size = file.metadata().unwrap().len();
  225. let mut crc = crc32::Digest::new(crc32::IEEE);
  226. let mut buf = [0u8; 1024 * 32];
  227. let mut reader = io::BufReader::new(file);
  228. while let Ok(len) = reader.read(&mut buf) {
  229. if len == 0 {
  230. break;
  231. }
  232. crc.write(&buf[0..len]);
  233. }
  234. Ok((crc.sum32(), size as u32))
  235. }
  236. fn does_file_need_updating(file_info: &FileInfoReply, patch_file_lookup: &HashMap<u32, PatchFile>) -> bool {
  237. let patch_file = patch_file_lookup.get(&file_info.id).unwrap();
  238. patch_file.checksum != file_info.checksum || patch_file.size != file_info.size
  239. }
  240. struct SendFileIterator {
  241. done: bool,
  242. file_iter: Box<dyn Iterator<Item = PatchTreeIterItem>>,
  243. file_ids_to_update: HashSet<u32>,
  244. patch_file_lookup: HashMap<u32, PatchFile>,
  245. current_file: Option<io::BufReader<fs::File>>,
  246. chunk_num: u32,
  247. }
  248. impl SendFileIterator {
  249. fn new(state: &PatchServerState) -> SendFileIterator {
  250. let file_ids_to_update = state.patch_file_info.iter()
  251. .filter(|file_info| does_file_need_updating(file_info, &state.patch_file_lookup))
  252. .map(|k| k.id)
  253. .collect::<HashSet<_>>();
  254. SendFileIterator {
  255. done: false,
  256. file_ids_to_update: file_ids_to_update,
  257. patch_file_lookup: state.patch_file_lookup.clone(),
  258. file_iter: Box::new(state.patch_file_tree.flatten().into_iter()),
  259. current_file: None,
  260. chunk_num: 0,
  261. }
  262. }
  263. }
  264. impl Iterator for SendFileIterator {
  265. type Item = SendPatchPacket;
  266. fn next(&mut self) -> Option<Self::Item> {
  267. if self.done {
  268. return None;
  269. }
  270. match self.current_file {
  271. Some(ref mut file) => {
  272. let mut buf = [0u8; PATCH_FILE_CHUNK_SIZE as usize];
  273. let len = file.read(&mut buf).unwrap();
  274. if len == 0 {
  275. self.current_file = None;
  276. self.chunk_num = 0;
  277. Some(SendPatchPacket::EndFileSend(EndFileSend::new()))
  278. }
  279. else {
  280. let mut crc = crc32::Digest::new(crc32::IEEE);
  281. crc.write(&buf[0..len]);
  282. let pkt = SendPatchPacket::FileSend(FileSend {
  283. chunk_num: self.chunk_num,
  284. checksum: crc.sum32(),
  285. chunk_size: len as u32,
  286. buffer: buf,
  287. });
  288. self.chunk_num += 1;
  289. Some(pkt)
  290. }
  291. },
  292. None => {
  293. match self.file_iter.next() {
  294. Some(next_file) => {
  295. match next_file {
  296. PatchTreeIterItem::Directory(path) => {
  297. Some(SendPatchPacket::ChangeDirectory(ChangeDirectory::new(path.to_str().unwrap())))
  298. },
  299. PatchTreeIterItem::File(path, id) => {
  300. if self.file_ids_to_update.contains(&id) {
  301. let patch_file = self.patch_file_lookup.get(&id).unwrap();
  302. let file = fs::File::open(&patch_file.path).unwrap();
  303. let size = file.metadata().unwrap().len();
  304. self.current_file = Some(io::BufReader::new(file));
  305. Some(SendPatchPacket::StartFileSend(StartFileSend::new(path.to_str().unwrap(), size as u32, id)))
  306. }
  307. else {
  308. self.next()
  309. }
  310. },
  311. PatchTreeIterItem::UpDirectory => {
  312. Some(SendPatchPacket::UpOneDirectory(UpOneDirectory {}))
  313. },
  314. }
  315. },
  316. None => {
  317. self.current_file = None;
  318. self.done = true;
  319. Some(SendPatchPacket::FinalizePatching(FinalizePatching {}))
  320. }
  321. }
  322. }
  323. }
  324. }
  325. }
  326. #[derive(Debug, Deserialize)]
  327. pub struct PatchConfig {
  328. pub path: String,
  329. pub ip: String,
  330. pub port: u16,
  331. }
  332. pub fn load_config() -> PatchConfig {
  333. let ini_file = match fs::File::open(std::path::Path::new("patch.ron")) {
  334. Err(err) => panic!("Failed to open patch.ron config file. \n{}", err),
  335. Ok(ini_file) => ini_file,
  336. };
  337. let mut s = String::new();
  338. if let Err(err) = (&ini_file).read_to_string(&mut s) {
  339. panic!("Failed to read patch.ron config file. \n{}", err);
  340. }
  341. let config: PatchConfig = match from_str(s.as_str()) {
  342. Ok(config) => config,
  343. Err(err) => panic!("Failed to load values from patch.ron \n{}",err),
  344. };
  345. config
  346. }