-use std::io::{ Acceptor, Listener, TcpStream, IoResult, IoError, EndOfFile };
+use std::io;
+use std::io::{ MemWriter, Acceptor, Listener, TcpStream, IoResult, IoError, EndOfFile };
use std::io::net::tcp::{ TcpAcceptor, TcpListener };
use packet;
use packet::{ Packet, Command, Answer, Error, ReadingResult, PacketType };
+// Default timeout when waiting data on a stream (for instance: 'TcpStream::read').
+static DEFAULT_TIMEOUT: Option<u64> = Some(500); // [ms].
+
pub struct Server {
acceptor: TcpAcceptor
}
}
impl Server {
- pub fn new(port: u16) -> IoResult<Server> {
- let mut acceptor = try!(TcpListener::bind("127.0.0.1", port).listen());
-
- let server = Server {
+ pub fn new(interface: &str, port: u16) -> IoResult<Server> {
+ let mut acceptor = try!(TcpListener::bind(interface, port).listen());
+
+ let server = Server {
acceptor: acceptor.clone()
};
-
+
spawn(proc() {
loop {
for stream in acceptor.incoming() {
match stream {
- Err(_) => return,
Ok(stream) => spawn(proc() {
Server::handle_client(EndPoint { socket: stream, current_timestamp: 0 });
- })
+ }),
+ _ => return
}
}
}
});
-
+
Ok(server)
}
-
+
pub fn close(&mut self) -> IoResult<()> {
self.acceptor.close_accept()
}
-
- fn handle_client(mut end_point: EndPoint) {
+
+ fn handle_client(mut end_point: EndPoint) {
loop {
- match end_point.read() {
+ match end_point.read() {
Ok(packet@Packet { t: Command(..), .. }) => {
println!("[Server] Valid command received: {}", packet);
- let answer = Answer(Packet::random_packet_data());
+ let answer = Answer(Packet::random_packet_data([]));
match end_point.send(answer.clone()) {
Ok(_) =>
println!("[Server] Answer sent: {}", answer),
other =>
println!("[Server] Error or invalid packet: {}", other)
}
- }
+ }
}
}
current_timestamp: 0
}})
}
-
+
pub fn close(&mut self) -> IoResult<()> {
self.end_point.close()
}
-
+
pub fn send(&mut self, packet: PacketType) {
match packet {
Command(_) => {
println!("[Client] Cannot send this type of packet: {}", other)
}
}
+
+ /// Send some valid and not-valid packets to the server and check the result.
+ /// For each test a new client is created.
+ pub fn start_tests(address: &str, port: u16) {
+ let execute = |f: &mut |&mut Client| -> bool| -> bool {
+ match Client::new(address, port) {
+ Ok(ref mut client) => (*f)(client),
+ Err(e) => {
+ println!("Unable to create a client. Error: {}", e);
+ false
+ }
+ }
+ };
+
+ fn raw_packet(timestamp: u64) -> Vec<u8> {
+ let mut m = MemWriter::new();
+ match (Packet { t: Command(Packet::random_packet_data([42])), timestamp: timestamp }).write(&mut m) {
+ Err(_) => vec!(),
+ _ => m.unwrap()
+ }
+ }
+
+ let mut tests = vec!(
+ // 1)
+ |client: &mut Client| -> bool {
+ println!("Sending a valid packet...");
+ match client.end_point.send_with_result(Command(Packet::random_packet_data([42]))) {
+ Ok(Ok(Packet { t: Answer(..), .. })) => true,
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+ // 2)
+ |client: &mut Client| -> bool {
+ println!("Sending a packet with an unknown type...");
+ client.end_point.current_timestamp += 1;
+ let mut raw_packet = raw_packet(client.end_point.current_timestamp);
+ raw_packet[2] = 0xEE; // Alter the type.
+ match client.end_point.send_raw_with_result(raw_packet.as_slice()) {
+ Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+ // 3)
+ |client: &mut Client| -> bool {
+ println!("Sending a packet with an old timestamp...");
+ client.end_point.current_timestamp += 1;
+ let raw_packet = raw_packet(0);
+ match client.end_point.send_raw_with_result(raw_packet.as_slice()) {
+ Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+ // 4)
+ |client: &mut Client| -> bool {
+ println!("Sending a packet with altered crypted data (do not alter the padding)...");
+ client.end_point.current_timestamp += 1;
+ let mut raw_packet = raw_packet(client.end_point.current_timestamp);
+ raw_packet[11] = 0xDE;
+ raw_packet[12] = 0xAD;
+ raw_packet[13] = 0xBE;
+ raw_packet[14] = 0xEF;
+ match client.end_point.send_raw_with_result(raw_packet.as_slice()) {
+ Ok(Ok(Packet { t: Error(packet::AuthError), .. })) => true,
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+ // 5)
+ |client: &mut Client| -> bool {
+ println!("Sending a packet with too small data...");
+ let command = Command(Packet::new_packet_data(0, Vec::from_elem(6, 0x00)));
+ match client.end_point.send_with_result(command) {
+ Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+ // 6)
+ |client: &mut Client| -> bool {
+ println!("Sending a packet with too large data...");
+ let command = Command(Packet::new_packet_data(0, Vec::from_elem(40, 0x00)));
+ match client.end_point.send_with_result(command) {
+ Ok(Err(packet::IOReadError( IoError { kind: io::TimedOut, .. }))) => true, // OK: the server should not send any packet.
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+ // 7)
+ |client: &mut Client| -> bool {
+ println!("Sending a packet with wrong padding (all 0)...");
+ client.end_point.current_timestamp += 1;
+ let mut m = MemWriter::new();
+ let raw_packet = match (Packet { t: Command(Packet::random_packet_data([42])), timestamp: client.end_point.current_timestamp }).write_with_padding_fun(&mut m, |_, _| -> u8 { 0 }) {
+ Err(_) => vec!(),
+ _ => m.unwrap()
+ };
+
+ match client.end_point.send_raw_with_result(raw_packet.as_slice()) {
+ Ok(Ok(Packet { t: Error(packet::CryptError), .. })) => true,
+ other => {
+ println!("Error: {}", other);
+ false
+ }
+ }
+ },
+ );
+
+ let mut nb_test_passed = 0;
+ for (i, test) in range(1, tests.len()+1).zip(tests.iter_mut()) {
+ println!("===== Test case #{}:", i)
+ if execute(test) {
+ nb_test_passed += 1;
+ println!("===== Test passed");
+ } else {
+ println!("===== Test failed");
+ }
+ }
+
+ if nb_test_passed == tests.len() {
+ println!("All tests passed");
+ } else {
+ println!("#{} test(s) failed", tests.len() - nb_test_passed);
+ }
+ }
}
-impl EndPoint {
+impl EndPoint {
fn close(&mut self) -> IoResult<()> {
try!(self.socket.close_read());
try!(self.socket.close_write());
Ok(())
}
-
- /**
- * Send a packet and wait synchronously an answer.
- */
+
+ /// Send a packet and wait for an answer synchronously.
fn send_with_result(&mut self, p: PacketType) -> IoResult<ReadingResult> {
match self.send(p) {
Err(e) => Err(e),
_ => Ok(self.read())
}
}
-
+
+ /// Send arbitrary data and wait for an answer synchronously.
+ /// Do not increment the current timestamp.
+ fn send_raw_with_result(&mut self, p: &[u8]) -> IoResult<ReadingResult> {
+ self.socket.set_timeout(DEFAULT_TIMEOUT);
+ match self.socket.write(p) {
+ Err(e) => Err(e),
+ _ => Ok(self.read())
+ }
+ }
+
fn send(&mut self, p: PacketType) -> IoResult<()> {
+ self.socket.set_timeout(DEFAULT_TIMEOUT);
self.current_timestamp += 1;
match (Packet { t: p, timestamp: self.current_timestamp }).write(&mut self.socket) {
- Ok(_) => Ok(()),
- Err(packet::WriteIOError(e)) => Err(e)
+ Err(packet::WriteIOError(e)) => Err(e),
+ _ => Ok(())
}
}
-
+
fn read(&mut self) -> ReadingResult {
fn send_error(ep: &mut EndPoint, error_type: packet::ErrorType) {
match ep.send(Error(error_type)) {
Ok(_) => ()
};
};
-
+
+ self.socket.set_timeout(DEFAULT_TIMEOUT);
match Packet::read(&mut self.socket) {
Ok(packet) => {
if packet.timestamp <= self.current_timestamp {
println!("Error, timestamp mismatch, current timestamp: {}, packet received: {}", self.current_timestamp, packet);
- Err(packet::InvalidTimestamp)
+ Err(packet::InvalidTimestampError)
} else {
self.current_timestamp = packet.timestamp + 1;
Ok(packet)
}
},
e @ Err(packet::PaddingError) => {
+ self.current_timestamp += 1;
send_error(self, packet::CryptError);
e
},
e @ Err(packet::MACMismatchError) => {
+ self.current_timestamp += 1;
send_error(self, packet::AuthError);
e
},
other
}
}
-}
\ No newline at end of file
+}