use libpso::crypto::{PSOCipher, NullCipher}; use libpso::{PSOPacket, PacketParseError}; use crate::common::serverstate::{ServerState, ServerPacket, OnConnect}; use crate::common::network::{recv_packet, PacketNetworkError}; use std::net; use std::io::Write; use mio::tcp::TcpStream; use mio::{Poll, Events, Token, Ready, PollOpt}; pub struct Client
{
running: bool,
socket: mio::tcp::TcpStream,
cipher_in: Box {
pub fn new(socket: mio::tcp::TcpStream, state: Box {
let mut client = Client {
running: true,
socket: socket,
cipher_in: Box::new(NullCipher {}),
cipher_out: Box::new(NullCipher {}),
state: state,
send_buffer: Vec::new(),
};
for task in client.state.on_connect() {
match task {
OnConnect::Packet(pkt) => client.send(&*pkt),
OnConnect::Cipher((cipher_in, cipher_out)) => {
client.cipher_in = cipher_in;
client.cipher_out = cipher_out;
},
}
}
client
}
fn send_data(&mut self) {
if self.send_buffer.len() == 0 {
return;
}
match self.socket.write(&self.send_buffer) {
Ok(len) => {
if len == 0 {
self.running = false;
}
self.send_buffer.drain(..len);
},
Err(err) => {
println!("[client] error sending data to {:?}: {:?}", self.socket, err);
}
}
}
// TODO: this may need to pad to 8 bytes for bb cipher
fn send(&mut self, pkt: &dyn PSOPacket) {
let buf = pkt.as_bytes();
let mut cbuf = self.cipher_out.encrypt(&buf).unwrap();
self.send_buffer.append(&mut cbuf);
self.send_data();
}
pub fn io_loop(mut self) {
let poll = Poll::new().unwrap();
poll.register(&self.socket, Token(0), Ready::readable() | Ready::writable(), PollOpt::edge()).unwrap();
let mut events = Events::with_capacity(1024);
while self.running {
poll.poll(&mut events, None).unwrap();
for event in &events{
if event.token() == Token(0) {
if event.readiness().is_writable() {
self.send_data();
}
if event.readiness().is_readable() {
loop {
let pkt = recv_packet(&mut self.socket, &mut *self.cipher_in)
.and_then(|pkt| {
P::from_bytes(&pkt)
.map_err(|err| err.into())
});
match pkt {
Ok(pkt) => {
let response = self.state.handle(&pkt);
for r in response {
self.send(&*r);
}
},
Err(err) => {
match err {
PacketNetworkError::ClientDisconnected => self.running = false,
_ => println!("error recv-ing packet with {:?}: {:?}", self.socket, err),
}
break;
}
}
}
}
}
}
}
}
}