Browse Source

Start implementing Proto{De,En}code for server requests.

wip
Titouan Rigoudy 7 years ago
parent
commit
c6b28958c0
1 changed files with 188 additions and 24 deletions
  1. +188
    -24
      src/proto/server/request.rs

+ 188
- 24
src/proto/server/request.rs View File

@ -3,14 +3,25 @@ use std::io;
use crypto::md5::Md5; use crypto::md5::Md5;
use crypto::digest::Digest; use crypto::digest::Digest;
use super::constants::*;
use super::super::packet::{MutPacket, WriteToPacket};
use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder};
use proto::packet::{MutPacket, WriteToPacket};
use proto::server::constants::*;
/* ------- *
* Helpers *
* ------- */
fn md5_str(string: &str) -> String {
let mut hasher = Md5::new();
hasher.input_str(string);
hasher.result_str()
}
/*================* /*================*
* SERVER REQUEST * * SERVER REQUEST *
*================*/ *================*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub enum ServerRequest { pub enum ServerRequest {
CannotConnectRequest(CannotConnectRequest), CannotConnectRequest(CannotConnectRequest),
ConnectToPeerRequest(ConnectToPeerRequest), ConnectToPeerRequest(ConnectToPeerRequest),
@ -86,17 +97,11 @@ impl WriteToPacket for ServerRequest {
} }
} }
fn md5_str(string: &str) -> String {
let mut hasher = Md5::new();
hasher.input_str(string);
hasher.result_str()
}
/*================* /*================*
* CANNOT CONNECT * * CANNOT CONNECT *
*================*/ *================*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct CannotConnectRequest { pub struct CannotConnectRequest {
pub token: u32, pub token: u32,
pub user_name: String, pub user_name: String,
@ -110,11 +115,29 @@ impl WriteToPacket for CannotConnectRequest {
} }
} }
impl ProtoEncode for CannotConnectRequest {
fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> {
encoder.encode_u32(self.token)?;
encoder.encode_string(&self.user_name)
}
}
impl ProtoDecode for CannotConnectRequest {
fn decode(decoder: &mut ProtoDecoder) -> Result<Self, DecodeError> {
let token = decoder.decode_u32()?;
let user_name = decoder.decode_string()?;
Ok(Self {
token: token,
user_name: user_name,
})
}
}
/*=================* /*=================*
* CONNECT TO PEER * * CONNECT TO PEER *
*=================*/ *=================*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct ConnectToPeerRequest { pub struct ConnectToPeerRequest {
pub token: u32, pub token: u32,
pub user_name: String, pub user_name: String,
@ -130,11 +153,32 @@ impl WriteToPacket for ConnectToPeerRequest {
} }
} }
impl ProtoEncode for ConnectToPeerRequest {
fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> {
encoder.encode_u32(self.token)?;
encoder.encode_string(&self.user_name)?;
encoder.encode_string(&self.connection_type)
}
}
impl ProtoDecode for ConnectToPeerRequest {
fn decode(decoder: &mut ProtoDecoder) -> Result<Self, DecodeError> {
let token = decoder.decode_u32()?;
let user_name = decoder.decode_string()?;
let connection_type = decoder.decode_string()?;
Ok(Self {
token: token,
user_name: user_name,
connection_type: connection_type,
})
}
}
/*=============* /*=============*
* FILE SEARCH * * FILE SEARCH *
*=============*/ *=============*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct FileSearchRequest { pub struct FileSearchRequest {
pub ticket: u32, pub ticket: u32,
pub query: String, pub query: String,
@ -148,18 +192,42 @@ impl WriteToPacket for FileSearchRequest {
} }
} }
impl ProtoEncode for FileSearchRequest {
fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> {
encoder.encode_u32(self.ticket)?;
encoder.encode_string(&self.query)
}
}
impl ProtoDecode for FileSearchRequest {
fn decode(decoder: &mut ProtoDecoder) -> Result<Self, DecodeError> {
let ticket = decoder.decode_u32()?;
let query = decoder.decode_string()?;
Ok(Self {
ticket: ticket,
query: query,
})
}
}
/*=======* /*=======*
* LOGIN * * LOGIN *
*=======*/ *=======*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct LoginRequest { pub struct LoginRequest {
username: String, username: String,
password: String, password: String,
digest: String,
major: u32, major: u32,
minor: u32, minor: u32,
} }
fn userpass_md5(username: &str, password: &str) -> String {
let userpass = String::new() + username + password;
md5_str(&userpass)
}
impl LoginRequest { impl LoginRequest {
pub fn new( pub fn new(
username: &str, username: &str,
@ -171,6 +239,7 @@ impl LoginRequest {
Ok(LoginRequest { Ok(LoginRequest {
username: username.to_string(), username: username.to_string(),
password: password.to_string(), password: password.to_string(),
digest: userpass_md5(username, password),
major: major, major: major,
minor: minor, minor: minor,
}) })
@ -178,28 +247,55 @@ impl LoginRequest {
Err("Empty password") Err("Empty password")
} }
} }
fn has_correct_digest(&self) -> bool {
self.digest == userpass_md5(&self.username, &self.password)
}
} }
impl WriteToPacket for LoginRequest { impl WriteToPacket for LoginRequest {
fn write_to_packet(&self, packet: &mut MutPacket) -> io::Result<()> { fn write_to_packet(&self, packet: &mut MutPacket) -> io::Result<()> {
let userpass = String::new() + &self.username + &self.password;
let userpass_md5 = md5_str(&userpass);
try!(packet.write_value(&self.username)); try!(packet.write_value(&self.username));
try!(packet.write_value(&self.password)); try!(packet.write_value(&self.password));
try!(packet.write_value(&self.major)); try!(packet.write_value(&self.major));
try!(packet.write_value(&userpass_md5));
try!(packet.write_value(&self.digest));
try!(packet.write_value(&self.minor)); try!(packet.write_value(&self.minor));
Ok(()) Ok(())
} }
} }
impl ProtoEncode for LoginRequest {
fn encode(&self, encoder: &mut ProtoEncoder) -> Result<(), io::Error> {
encoder.encode_string(&self.username)?;
encoder.encode_string(&self.password)?;
encoder.encode_u32(self.major)?;
encoder.encode_string(&self.digest)?;
encoder.encode_u32(self.minor)
}
}
impl ProtoDecode for LoginRequest {
fn decode(decoder: &mut ProtoDecoder) -> Result<Self, DecodeError> {
let username = decoder.decode_string()?;
let password = decoder.decode_string()?;
let major = decoder.decode_u32()?;
let digest = decoder.decode_string()?;
let minor = decoder.decode_u32()?;
Ok(Self {
username: username,
password: password,
digest: digest,
major: major,
minor: minor,
})
}
}
/*==============* /*==============*
* PEER ADDRESS * * PEER ADDRESS *
*==============*/ *==============*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct PeerAddressRequest { pub struct PeerAddressRequest {
pub username: String, pub username: String,
} }
@ -215,7 +311,7 @@ impl WriteToPacket for PeerAddressRequest {
* ROOM JOIN * * ROOM JOIN *
*===========*/ *===========*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct RoomJoinRequest { pub struct RoomJoinRequest {
pub room_name: String, pub room_name: String,
} }
@ -231,7 +327,7 @@ impl WriteToPacket for RoomJoinRequest {
* ROOM LEAVE * * ROOM LEAVE *
*============*/ *============*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct RoomLeaveRequest { pub struct RoomLeaveRequest {
pub room_name: String, pub room_name: String,
} }
@ -247,7 +343,7 @@ impl WriteToPacket for RoomLeaveRequest {
* ROOM MESSAGE * * ROOM MESSAGE *
*==============*/ *==============*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct RoomMessageRequest { pub struct RoomMessageRequest {
pub room_name: String, pub room_name: String,
pub message: String, pub message: String,
@ -265,7 +361,7 @@ impl WriteToPacket for RoomMessageRequest {
* SET LISTEN PORT * * SET LISTEN PORT *
*=================*/ *=================*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct SetListenPortRequest { pub struct SetListenPortRequest {
pub port: u16, pub port: u16,
} }
@ -281,7 +377,7 @@ impl WriteToPacket for SetListenPortRequest {
* USER STATUS * * USER STATUS *
*=============*/ *=============*/
#[derive(Debug)]
#[derive(Debug, Eq, PartialEq)]
pub struct UserStatusRequest { pub struct UserStatusRequest {
pub user_name: String, pub user_name: String,
} }
@ -292,3 +388,71 @@ impl WriteToPacket for UserStatusRequest {
Ok(()) Ok(())
} }
} }
#[cfg(test)]
mod tests {
use std::fmt::Debug;
use std::io;
use bytes::BytesMut;
use proto::{DecodeError, ProtoDecode, ProtoDecoder, ProtoEncode, ProtoEncoder};
use super::*;
fn roundtrip<T: Debug + Eq + ProtoDecode + ProtoEncode>(input: &T) -> T {
let mut bytes = BytesMut::new();
input.encode(&mut ProtoEncoder::new(&mut bytes)).unwrap();
let mut cursor = io::Cursor::new(bytes);
T::decode(&mut ProtoDecoder::new(&mut cursor)).unwrap()
}
#[test]
fn roundtrip_cannot_connect_request() {
let input = CannotConnectRequest {
token: 1337,
user_name: "alice".to_string(),
};
assert_eq!(roundtrip(&input), input);
}
#[test]
fn roundtrip_connect_to_peer_request() {
let input = ConnectToPeerRequest {
token: 1337,
user_name: "alice".to_string(),
connection_type: "P".to_string(),
};
assert_eq!(roundtrip(&input), input);
}
#[test]
fn roundtrip_file_search_request() {
let input = FileSearchRequest {
ticket: 1337,
query: "foo.txt".to_string(),
};
assert_eq!(roundtrip(&input), input);
}
#[test]
#[should_panic]
fn new_login_request_with_empty_password() {
LoginRequest::new("alice", "", 1337, 42).unwrap();
}
#[test]
fn new_login_request_has_correct_digest() {
let request = LoginRequest::new("alice", "password1234", 1337, 42).unwrap();
assert!(request.has_correct_digest());
}
#[test]
fn roundtrip_login_request() {
let input = LoginRequest::new("alice", "password1234", 1337, 42).unwrap();
let output = roundtrip(&input);
assert_eq!(output, input);
assert!(output.has_correct_digest());
}
}

Loading…
Cancel
Save