properly separate clients in characterlogin server handling
This commit is contained in:
		
							parent
							
								
									a23a300a26
								
							
						
					
					
						commit
						b174a5a759
					
				| @ -1,6 +1,7 @@ | |||||||
| use std::net; | use std::net; | ||||||
| use std::sync::Arc; | use std::sync::Arc; | ||||||
| use std::io::Read; | use std::io::Read; | ||||||
|  | use std::collections::HashMap; | ||||||
| 
 | 
 | ||||||
| use rand::{Rng, RngCore}; | use rand::{Rng, RngCore}; | ||||||
| use bcrypt::{DEFAULT_COST, hash, verify}; | use bcrypt::{DEFAULT_COST, hash, verify}; | ||||||
| @ -29,6 +30,7 @@ pub const CHARACTER_PORT: u16 = 12001; | |||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| pub enum CharacterError { | pub enum CharacterError { | ||||||
|  |     ClientNotFound(ClientId), | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| #[derive(Debug)] | #[derive(Debug)] | ||||||
| @ -123,18 +125,29 @@ fn generate_param_data(path: &str) -> (ParamDataHeader, Vec<u8>) { | |||||||
|     }, buffer) |     }, buffer) | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| // TODO: rip these client-specific vars into a HashMap<ClientId, ClientState>
 | struct ClientState { | ||||||
| pub struct CharacterServerState<DA: DataAccess> { |  | ||||||
|     //shared_state: SharedLoginState<DA>,
 |  | ||||||
|     data_access: DA, |  | ||||||
|     param_header: ParamDataHeader, |  | ||||||
| 
 |  | ||||||
|     param_index: usize, |     param_index: usize, | ||||||
|     param_data: Arc<Vec<u8>>, |  | ||||||
|     user: Option<UserAccount>, |     user: Option<UserAccount>, | ||||||
|     characters: Option<[Option<Character>; 4]>, |     characters: Option<[Option<Character>; 4]>, | ||||||
|     guildcard_data_buffer: Option<Vec<u8>>, |     guildcard_data_buffer: Option<Vec<u8>>, | ||||||
|  | } | ||||||
| 
 | 
 | ||||||
|  | impl ClientState { | ||||||
|  |     fn new() -> ClientState { | ||||||
|  |         ClientState { | ||||||
|  |             param_index: 0, | ||||||
|  |             user: None, | ||||||
|  |             characters: None, | ||||||
|  |             guildcard_data_buffer: None, | ||||||
|  |         } | ||||||
|  |     } | ||||||
|  | } | ||||||
|  | 
 | ||||||
|  | pub struct CharacterServerState<DA: DataAccess> { | ||||||
|  |     data_access: DA, | ||||||
|  |     param_header: ParamDataHeader, | ||||||
|  |     param_data: Vec<u8>, | ||||||
|  |     clients: HashMap<ClientId, ClientState>, | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| impl<DA: DataAccess> CharacterServerState<DA> { | impl<DA: DataAccess> CharacterServerState<DA> { | ||||||
| @ -145,32 +158,32 @@ impl<DA: DataAccess> CharacterServerState<DA> { | |||||||
|             //shared_state: shared_state,
 |             //shared_state: shared_state,
 | ||||||
|             data_access: data_access, |             data_access: data_access, | ||||||
|             param_header: param_header, |             param_header: param_header, | ||||||
| 
 |             param_data: param_data, | ||||||
|             param_index: 0, |             clients: HashMap::new(), | ||||||
|             param_data: Arc::new(param_data), |  | ||||||
|             user: None, |  | ||||||
|             characters: None, |  | ||||||
|             guildcard_data_buffer: None, |  | ||||||
|         } |         } | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn validate_login(&mut self, pkt: &Login) -> Vec<SendCharacterPacket> { |     fn validate_login(&mut self, id: ClientId, pkt: &Login) -> Result<Vec<SendCharacterPacket>, CharacterError> { | ||||||
|         match get_login_status(&self.data_access, pkt) { |         let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; | ||||||
|  |         Ok(match get_login_status(&self.data_access, pkt) { | ||||||
|             Ok(user) => { |             Ok(user) => { | ||||||
|                 let mut response = LoginResponse::by_status(AccountStatus::Ok, pkt.security_data); |                 let mut response = LoginResponse::by_status(AccountStatus::Ok, pkt.security_data); | ||||||
|                 response.guildcard = user.guildcard.map_or(0, |gc| gc) as u32; |                 response.guildcard = user.guildcard.map_or(0, |gc| gc) as u32; | ||||||
|                 response.team_id = user.team_id.map_or(0, |ti| ti) as u32; |                 response.team_id = user.team_id.map_or(0, |ti| ti) as u32; | ||||||
|                 self.user = Some(user); |                 client.user = Some(user); | ||||||
|                 vec![SendCharacterPacket::LoginResponse(response)] |                 vec![SendCharacterPacket::LoginResponse(response)] | ||||||
|             }, |             }, | ||||||
|             Err(err) => { |             Err(err) => { | ||||||
|                 vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, pkt.security_data))] |                 vec![SendCharacterPacket::LoginResponse(LoginResponse::by_status(err, pkt.security_data))] | ||||||
|             } |             } | ||||||
|         } |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn get_settings(&mut self) -> Vec<SendCharacterPacket> { |     fn get_settings(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, CharacterError> { | ||||||
|         let user = self.user.as_ref().unwrap(); |         let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; | ||||||
|  |         let user = client.user.as_ref().unwrap(); | ||||||
|  | 
 | ||||||
|  |         // TODO: this should error (data should be added on account creation, why did I copy this silly sylv logic?)
 | ||||||
|         let settings = match self.data_access.get_user_settings_by_user(&user) { |         let settings = match self.data_access.get_user_settings_by_user(&user) { | ||||||
|             Some(settings) => settings, |             Some(settings) => settings, | ||||||
|             None => self.data_access.create_user_settings_by_user(&user), |             None => self.data_access.create_user_settings_by_user(&user), | ||||||
| @ -180,16 +193,17 @@ impl<DA: DataAccess> CharacterServerState<DA> { | |||||||
|                                               settings.settings.joystick_config, 0, 0); |                                               settings.settings.joystick_config, 0, 0); | ||||||
|         let pkt = SendCharacterPacket::SendKeyAndTeamSettings(pkt); |         let pkt = SendCharacterPacket::SendKeyAndTeamSettings(pkt); | ||||||
| 
 | 
 | ||||||
|         vec![pkt] |         Ok(vec![pkt]) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn char_select(&mut self, select: &CharSelect) -> Vec<SendCharacterPacket> { |     fn char_select(&mut self, id: ClientId, select: &CharSelect) -> Result<Vec<SendCharacterPacket>, CharacterError> { | ||||||
|         if self.characters.is_none() { |         let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; | ||||||
|             self.characters = Some(self.data_access.get_characters_by_user(self.user.as_ref().unwrap())); |         if client.characters.is_none() { | ||||||
|  |             client.characters = Some(self.data_access.get_characters_by_user(client.user.as_ref().unwrap())); | ||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let chars = self.characters.as_ref().unwrap(); |         let chars = client.characters.as_ref().unwrap(); | ||||||
|         if let Some(char) = &chars[select.slot as usize] { |         Ok(if let Some(char) = &chars[select.slot as usize] { | ||||||
|             vec![SendCharacterPacket::CharacterPreview(CharacterPreview { |             vec![SendCharacterPacket::CharacterPreview(CharacterPreview { | ||||||
|                 flag: 0, |                 flag: 0, | ||||||
|                 slot: select.slot, |                 slot: select.slot, | ||||||
| @ -202,7 +216,7 @@ impl<DA: DataAccess> CharacterServerState<DA> { | |||||||
|                 slot: select.slot, |                 slot: select.slot, | ||||||
|                 code: 2, |                 code: 2, | ||||||
|             })] |             })] | ||||||
|         } |         }) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn validate_checksum(&mut self) -> Vec<SendCharacterPacket> { |     fn validate_checksum(&mut self) -> Vec<SendCharacterPacket> { | ||||||
| @ -212,31 +226,32 @@ impl<DA: DataAccess> CharacterServerState<DA> { | |||||||
|         })] |         })] | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn guildcard_data_header(&mut self) -> Vec<SendCharacterPacket> { |     fn guildcard_data_header(&mut self, id: ClientId) -> Result<Vec<SendCharacterPacket>, CharacterError> { | ||||||
|         let guildcard_data = self.data_access.get_guild_card_data_by_user(self.user.as_ref().unwrap()); |         let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; | ||||||
|  |         let guildcard_data = self.data_access.get_guild_card_data_by_user(client.user.as_ref().unwrap()); | ||||||
| 
 | 
 | ||||||
|         let bytes = guildcard_data.guildcard.as_bytes(); |         let bytes = guildcard_data.guildcard.as_bytes(); | ||||||
|         let mut crc = crc32::Digest::new(crc32::IEEE); |         let mut crc = crc32::Digest::new(crc32::IEEE); | ||||||
|         crc.write(&bytes[..]); |         crc.write(&bytes[..]); | ||||||
|         self.guildcard_data_buffer = Some(bytes.to_vec()); |         client.guildcard_data_buffer = Some(bytes.to_vec()); | ||||||
| 
 | 
 | ||||||
|         vec![SendCharacterPacket::GuildcardDataHeader(GuildcardDataHeader::new(bytes.len(), crc.sum32()))] |         Ok(vec![SendCharacterPacket::GuildcardDataHeader(GuildcardDataHeader::new(bytes.len(), crc.sum32()))]) | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn guildcard_data_chunk(&mut self, chunk: u32, again: u32) -> Vec<SendCharacterPacket> { |     fn guildcard_data_chunk(&mut self, id: ClientId, chunk: u32, again: u32) -> Result<Vec<SendCharacterPacket>, CharacterError> { | ||||||
|         if again != 0 { |         let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; | ||||||
|  |         Ok(if again != 0 { | ||||||
|             let start = chunk as usize * GUILD_CARD_CHUNK_SIZE; |             let start = chunk as usize * GUILD_CARD_CHUNK_SIZE; | ||||||
|             let len = std::cmp::min(GUILD_CARD_CHUNK_SIZE, self.guildcard_data_buffer.as_ref().unwrap().len() as usize - start); |             let len = std::cmp::min(GUILD_CARD_CHUNK_SIZE, client.guildcard_data_buffer.as_ref().unwrap().len() as usize - start); | ||||||
|             let end = start + len; |             let end = start + len; | ||||||
| 
 | 
 | ||||||
|             let mut buf = [0u8; GUILD_CARD_CHUNK_SIZE as usize]; |             let mut buf = [0u8; GUILD_CARD_CHUNK_SIZE as usize]; | ||||||
|             buf[..len as usize].copy_from_slice(&self.guildcard_data_buffer.as_ref().unwrap()[start..end]); |             buf[..len as usize].copy_from_slice(&client.guildcard_data_buffer.as_ref().unwrap()[start..end]); | ||||||
| 
 | 
 | ||||||
|             vec![SendCharacterPacket::GuildcardDataChunk(GuildcardDataChunk::new(chunk, buf, len))] |             vec![SendCharacterPacket::GuildcardDataChunk(GuildcardDataChunk::new(chunk, buf, len))] | ||||||
|         } else { |         } else { | ||||||
|             Vec::new() |             Vec::new() | ||||||
|         } |         }) | ||||||
| 
 |  | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
| } | } | ||||||
| @ -247,6 +262,8 @@ impl<DA: DataAccess> ServerState for CharacterServerState<DA> { | |||||||
|     type PacketError = CharacterError; |     type PacketError = CharacterError; | ||||||
| 
 | 
 | ||||||
|     fn on_connect(&mut self, id: ClientId) -> Vec<OnConnect<Self::SendPacket>> { |     fn on_connect(&mut self, id: ClientId) -> Vec<OnConnect<Self::SendPacket>> { | ||||||
|  |         self.clients.insert(id, ClientState::new()); | ||||||
|  | 
 | ||||||
|         let mut rng = rand::thread_rng(); |         let mut rng = rand::thread_rng(); | ||||||
| 
 | 
 | ||||||
|         let mut server_key = [0u8; 48]; |         let mut server_key = [0u8; 48]; | ||||||
| @ -260,32 +277,34 @@ impl<DA: DataAccess> ServerState for CharacterServerState<DA> { | |||||||
|         ] |         ] | ||||||
|     } |     } | ||||||
| 
 | 
 | ||||||
|     fn handle(&mut self, id: ClientId, pkt: &RecvCharacterPacket) -> Box<dyn Iterator<Item = (ClientId, SendCharacterPacket)>> { |     fn handle(&mut self, id: ClientId, pkt: &RecvCharacterPacket) | ||||||
|         match pkt { |               -> Result<Box<dyn Iterator<Item = (ClientId, SendCharacterPacket)>>, CharacterError> { | ||||||
|  |         Ok(match pkt { | ||||||
|             RecvCharacterPacket::Login(login) => { |             RecvCharacterPacket::Login(login) => { | ||||||
|                 Box::new(self.validate_login(login).into_iter().map(move |pkt| (id, pkt))) |                 Box::new(self.validate_login(id, login)?.into_iter().map(move |pkt| (id, pkt))) | ||||||
|             }, |             }, | ||||||
|             RecvCharacterPacket::RequestSettings(_req) => { |             RecvCharacterPacket::RequestSettings(_req) => { | ||||||
|                 Box::new(self.get_settings().into_iter().map(move |pkt| (id, pkt))) |                 Box::new(self.get_settings(id)?.into_iter().map(move |pkt| (id, pkt))) | ||||||
|             }, |             }, | ||||||
|             RecvCharacterPacket::CharSelect(sel) => { |             RecvCharacterPacket::CharSelect(sel) => { | ||||||
|                 Box::new(self.char_select(sel).into_iter().map(move |pkt| (id, pkt))) |                 Box::new(self.char_select(id, sel)?.into_iter().map(move |pkt| (id, pkt))) | ||||||
|             }, |             }, | ||||||
|             RecvCharacterPacket::Checksum(_checksum) => { |             RecvCharacterPacket::Checksum(_checksum) => { | ||||||
|                 Box::new(self.validate_checksum().into_iter().map(move |pkt| (id, pkt))) |                 Box::new(self.validate_checksum().into_iter().map(move |pkt| (id, pkt))) | ||||||
|             }, |             }, | ||||||
|             RecvCharacterPacket::GuildcardDataRequest(_request) => { |             RecvCharacterPacket::GuildcardDataRequest(_request) => { | ||||||
|                 Box::new(self.guildcard_data_header().into_iter().map(move |pkt| (id, pkt))) |                 Box::new(self.guildcard_data_header(id)?.into_iter().map(move |pkt| (id, pkt))) | ||||||
|             }, |             }, | ||||||
|             RecvCharacterPacket::GuildcardDataChunkRequest(request) => { |             RecvCharacterPacket::GuildcardDataChunkRequest(request) => { | ||||||
|                 Box::new(self.guildcard_data_chunk(request.chunk, request.again).into_iter().map(move |pkt| (id, pkt))) |                 Box::new(self.guildcard_data_chunk(id, request.chunk, request.again)?.into_iter().map(move |pkt| (id, pkt))) | ||||||
|             }, |             }, | ||||||
|             RecvCharacterPacket::ParamDataRequest(_request) => { |             RecvCharacterPacket::ParamDataRequest(_request) => { | ||||||
|                 Box::new(vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt))) |                 Box::new(vec![SendCharacterPacket::ParamDataHeader(self.param_header.clone())].into_iter().map(move |pkt| (id, pkt))) | ||||||
|             }, |             }, | ||||||
|             RecvCharacterPacket::ParamDataChunkRequest(_request) => { |             RecvCharacterPacket::ParamDataChunkRequest(_request) => { | ||||||
|                 let chunk = self.param_index; |                 let client = self.clients.get_mut(&id).ok_or(CharacterError::ClientNotFound(id))?; | ||||||
|                 self.param_index += 1; |                 let chunk = client.param_index; | ||||||
|  |                 client.param_index += 1; | ||||||
| 
 | 
 | ||||||
|                 let start = chunk * 0x6800; |                 let start = chunk * 0x6800; | ||||||
|                 let end = std::cmp::min((chunk+1)*0x6800, self.param_data.len()); |                 let end = std::cmp::min((chunk+1)*0x6800, self.param_data.len()); | ||||||
| @ -301,7 +320,7 @@ impl<DA: DataAccess> ServerState for CharacterServerState<DA> { | |||||||
|                     } |                     } | ||||||
|                 )].into_iter().map(move |pkt| (id, pkt))) |                 )].into_iter().map(move |pkt| (id, pkt))) | ||||||
|             } |             } | ||||||
|         } |         }) | ||||||
|     } |     } | ||||||
| } | } | ||||||
| 
 | 
 | ||||||
| @ -328,7 +347,8 @@ mod test { | |||||||
|         } |         } | ||||||
| 
 | 
 | ||||||
|         let mut server = CharacterServerState::new(TestData {}); |         let mut server = CharacterServerState::new(TestData {}); | ||||||
|         server.user = Some(UserAccount { |         let mut clientstate = ClientState::new(); | ||||||
|  |         clientstate.user = Some(UserAccount { | ||||||
|             id: 1, |             id: 1, | ||||||
|             username: "testuser".to_owned(), |             username: "testuser".to_owned(), | ||||||
|             password: bcrypt::hash("mypassword", 5).unwrap(), |             password: bcrypt::hash("mypassword", 5).unwrap(), | ||||||
| @ -338,8 +358,11 @@ mod test { | |||||||
|             muted_until: SystemTime::now(), |             muted_until: SystemTime::now(), | ||||||
|             created_at: SystemTime::now(), |             created_at: SystemTime::now(), | ||||||
|         }); |         }); | ||||||
|  |         server.clients.insert(ClientId(5), clientstate); | ||||||
| 
 | 
 | ||||||
|         let send = server.handle(ClientId(5), &RecvCharacterPacket::RequestSettings(RequestSettings {flag: 0})).collect::<Vec<_>>(); |         let send = server.handle(ClientId(5), &RecvCharacterPacket::RequestSettings(RequestSettings {flag: 0})) | ||||||
|  |             .unwrap() | ||||||
|  |             .collect::<Vec<_>>(); | ||||||
|         assert!(send.len() == 1); |         assert!(send.len() == 1); | ||||||
| 
 | 
 | ||||||
|         assert!(send[0].0 == ClientId(5)); |         assert!(send[0].0 == ClientId(5)); | ||||||
| @ -356,7 +379,7 @@ mod test { | |||||||
|         let send = server.handle(ClientId(1), &RecvCharacterPacket::Checksum(Checksum {flag: 0, |         let send = server.handle(ClientId(1), &RecvCharacterPacket::Checksum(Checksum {flag: 0, | ||||||
|                                                                                        checksum: 1234, |                                                                                        checksum: 1234, | ||||||
|                                                                                        padding: 0, |                                                                                        padding: 0, | ||||||
|         })).collect::<Vec<_>>(); |         })).unwrap().collect::<Vec<_>>(); | ||||||
|         assert!(send.len() == 1); |         assert!(send.len() == 1); | ||||||
| 
 | 
 | ||||||
|         let bytes = send[0].1.as_bytes(); |         let bytes = send[0].1.as_bytes(); | ||||||
|  | |||||||
		Loading…
	
	
			
			x
			
			
		
	
		Reference in New Issue
	
	Block a user