diff --git a/build.rs b/build.rs index 30e9637..d6444e3 100644 --- a/build.rs +++ b/build.rs @@ -1,5 +1,5 @@ extern crate prost_build; fn main() { - prost_build::compile_protos(&["proto/notice.proto"], &["proto/"]).unwrap(); + prost_build::compile_protos(&["proto/netcomm.proto"], &["proto/"]).unwrap(); } diff --git a/proto/announcement.proto b/proto/announcement.proto index ecceee7..a51e943 100644 --- a/proto/announcement.proto +++ b/proto/announcement.proto @@ -5,7 +5,7 @@ package tm; import "division.proto"; message Announcement { optional string msg = 1; - optional .Division.DivisionId divId = 2 [default = ALL]; + optional tm.Division.DivisionId divId = 2 [default = ALL]; optional uint32 endTime = 3 [default = 0]; optional uint32 group = 4 [default = 0]; } diff --git a/src/main.rs b/src/main.rs index 9068fdc..14226e3 100644 --- a/src/main.rs +++ b/src/main.rs @@ -30,10 +30,6 @@ pub mod tm { include!(concat!(env!("OUT_DIR"), "/tm.rs")); } -pub fn deserialize_notice(buf: &[u8]) -> Result { - tm::Notice::decode(&mut Cursor::new(buf)) -} - #[derive(Serialize, Deserialize, Debug)] struct DivisionInfo { arena: String, @@ -261,7 +257,7 @@ struct ConnectMsg { } impl ConnectMsg { - fn from_welcome(welcome: ConnectMsg, password: &str, uuid: [u8; 16], client_name: [u8; 32]) -> ConnectMsg { + fn from_welcome(welcome: ConnectMsg, password: &str, uuid: [u8; 16], client_name: [u8; 32], username: [u8; 16]) -> ConnectMsg { let mut hasher = Sha256::new(); hasher.update(welcome.pass_hash); hasher.update(password); @@ -270,8 +266,15 @@ impl ConnectMsg { return ConnectMsg{ version: welcome.version, uuid, - last_notice_id: welcome.last_notice_id, - username: [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0], + // The TM returns state_valid=0 if last_notice_id < pendingNotices[0].id + // It looks like this check is basically to say "you can't connect if I sent you + // notices you weren't aware of" since in effect it prevents a client from connecting + // if it sends a last_notice_id less than what the TM expects + // To get around it you can just send the (max_u64 - 1) so that the check of + // (last_notice_id + 1) < pendingNotices[0].id always fails. + // The downside is that the TM will not send you any queued notices. + last_notice_id: 0xFFFFFFFFFFFFFFFF - 1, + username, pass_hash: result.try_into().unwrap(), pw_valid: welcome.pw_valid, state_valid: welcome.state_valid, @@ -315,6 +318,33 @@ impl ConnectMsg { } } +const NOTICE_MSG_LEN: usize = 8; +#[derive(Debug)] +struct NoticeMsg { + notice_id: u64, + notice: tm::Notice, +} + +impl NoticeMsg { + fn from_bytes(bytes: Vec) -> Option { + if bytes.len() < NOTICE_MSG_LEN { + return None; + } + + // TODO: figure out what protobuf is containing the notice so that I don't add a static + // offset + let mut pb_data = Cursor::new(bytes[8..].to_vec()); + match tm::Notice::decode(&mut pb_data) { + Ok(notice) => Some(NoticeMsg{ + notice_id: u64::from_le_bytes(bytes[0..8].try_into().unwrap()), + notice, + } + ), + Err(_) => None, + } + } +} + struct TMClient { stream: Arc>>, notices: mpsc::Sender, @@ -323,6 +353,7 @@ struct TMClient { client_name: [u8; 32], password: String, last_seq_num: u64, + username: [u8; 16], } struct TMConnection { @@ -332,7 +363,7 @@ struct TMConnection { } impl TMClient { - fn new(uuid: [u8; 16], client_name: [u8; 32], password: String) -> (TMClient, TMConnection) { + fn new(uuid: [u8; 16], client_name: [u8; 32], password: String, username: [u8; 16]) -> (TMClient, TMConnection) { let (notice_tx, notice_rx) = mpsc::channel(); let (response_tx, response_rx) = mpsc::channel(); @@ -361,6 +392,7 @@ impl TMClient { client_name, password, last_seq_num: 0xFFFFFFFFFFFFFFFF, + username, }, TMConnection{ stream: stream_arc, @@ -380,13 +412,34 @@ impl TMClient { Some(packet) => { self.last_seq_num = packet.seq_num; match packet.msg_type { + // Notice Message + 4 => { + match NoticeMsg::from_bytes(packet.data.clone()) { + Some(notice) => { + println!("Received notice: {:?}", notice); + let ack = BackendPacket::new(packet.header, packet.timestamp, 5, self.last_seq_num+1, notice.notice_id.to_le_bytes().to_vec()); + self.last_seq_num += 1; + match stream.write(&ack.as_bytes()) { + Ok(_) => println!("Sent ACK for notice {}", notice.notice_id), + Err(error) => println!("ACK error: {:?}", error), + } + }, + None => println!("Notice error: {:?}", packet), + } + }, + // Response message + 3 => { + println!("Received response. TODO: handle these"); + }, + // Server Message 2 => { match ConnectMsg::from_bytes(packet.data) { Some(welcome_msg) => { println!("Welcome msg: {:?}", welcome_msg); if welcome_msg.pw_valid == 0 { - let connect_response = ConnectMsg::from_welcome(welcome_msg, &self.password, self.uuid, self.client_name); + let connect_response = ConnectMsg::from_welcome(welcome_msg, &self.password, self.uuid, self.client_name, self.username); let response = BackendPacket::new(packet.header, packet.timestamp, packet.msg_type, self.last_seq_num+1, connect_response.as_bytes()); + println!("Sending {:X?}", connect_response); match stream.write(&response.as_bytes()) { Err(error) => println!("Send error: {:?}", error), Ok(sent) => { @@ -394,6 +447,8 @@ impl TMClient { self.last_seq_num += 1; }, } + } else if welcome_msg.state_valid == 0 { + println!("pw_valid but not state_valid"); } else { println!("Connected to TM backend!"); } @@ -405,7 +460,8 @@ impl TMClient { } }, None => { - panic!("Failed to parse BackendPacket({}): {}", read, String::from_utf8_lossy(&incoming)); + println!("Failed to parse BackendPacket({}): {}", read, String::from_utf8_lossy(&incoming)); + thread::sleep(Duration::from_millis(100)); } } }, @@ -530,6 +586,15 @@ fn on_match_list_update(notice: tm::Notice, event: Event) -> (Vec, fn main() { env_logger::init(); + let mut test = tm::Notice::default(); + test.set_id(tm::NoticeId::NoticeRankingsUpdated); + test.set_affected_round(tm::MatchRound::Qual); + let mut div = tm::Division::default(); + div.id = Some(1); + test.division = Some(div); + + println!("ENCODED_PROTOBUF: {:X?}", test.encode_to_vec()); + let mut event = Event{ name: String::from(""), divisions: Vec::new(), @@ -569,7 +634,8 @@ fn main() { let running = true; let uuid = [1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12, 13, 14, 15, 16]; let client_name: [u8;32] = [b'r', b'u', b's', b't', b'-', b'b', b'r', b'i', b'd', b'g', b'e', 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; - let (mut tm_client, tm_connection) = TMClient::new(uuid, client_name, String::from("")); + let username: [u8;16] = [0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0, 0]; + let (mut tm_client, tm_connection) = TMClient::new(uuid, client_name, String::from(""), username); let tm_thread = thread::spawn(move || while running { tm_client.process();