diff --git a/Cargo.lock b/Cargo.lock index 1796527..27bfa0f 100644 --- a/Cargo.lock +++ b/Cargo.lock @@ -204,6 +204,7 @@ dependencies = [ "base64", "rand", "sha1", + "ws_core", ] [[package]] diff --git a/ws_client/Cargo.toml b/ws_client/Cargo.toml index d394b8f..3be0d73 100644 --- a/ws_client/Cargo.toml +++ b/ws_client/Cargo.toml @@ -4,6 +4,7 @@ version = "0.1.0" edition = "2024" [dependencies] +ws_core = { path = "../ws_core" } rand = "0.9.2" base64 = "0.22.1" sha1="0.10.6" \ No newline at end of file diff --git a/ws_client/src/main.rs b/ws_client/src/main.rs index eed8f0b..976dbca 100644 --- a/ws_client/src/main.rs +++ b/ws_client/src/main.rs @@ -5,14 +5,15 @@ use base64::Engine; use base64::engine::general_purpose; use rand::Rng; use sha1::{Digest, Sha1}; +use ws_core::write::send_client_message; pub fn handle_server(mut stream: TcpStream) -> Result<()> { - let random_bs64_key =generate_base64_key(16); + let random_bs64_key = generate_base64_key(16); //send a http request to the server for upgrading the protocol from normal http to websocket stream.write_all( format!( - "GET / HTTP/1.1\r\n - Host: 127.0.0.1:8080\r\n + "GET / HTTP/1.1\r\n\ + Host: 127.0.0.1:8080\r\n\ Upgrade: websocket\r\n\ Connection: Upgrade\r\n\ Sec-WebSocket-Key: {}\r\n\ @@ -25,7 +26,7 @@ pub fn handle_server(mut stream: TcpStream) -> Result<()> { let mut buffer = Vec::new(); let mut temp = [0u8; 1024]; - //loop over all the streams and stop when we get CL RF CL RF + //loop over all the streams and stop when we get CL RF CL RF // this makes us read all the valid stream and stops us from breaking and reading only half streamed data loop { let bytes_read = stream.read(&mut temp).expect("failed to read the stream"); @@ -50,7 +51,7 @@ pub fn handle_server(mut stream: TcpStream) -> Result<()> { { let mut server_key = String::new(); - //get the server key which server sent for upgrading + //get the server key which server sent for upgrading for line in request.lines() { if line.starts_with("Sec-WebSocket-Accept:") { server_key = line.split(":").nth(1).unwrap().trim().to_string(); @@ -68,10 +69,25 @@ pub fn handle_server(mut stream: TcpStream) -> Result<()> { //match the expected key with the server key if yes then create a loop untill the connection closes if received_key == server_key { - loop { - - } - }else{ + loop { + let msg = "Hello, server".as_bytes(); + let fincode = 0b1000_0000; + let opcode = 0b0000_0001; + + let byte1 = fincode | opcode; + + let mut masking_key = [0u8; 4]; + rand::rng().fill(&mut masking_key[..]); + let mut encoded_data = vec![0u8; msg.len()]; + + for i in 0..msg.len() { + let idx: usize = i.try_into().unwrap(); + encoded_data[idx] = msg[idx] ^ masking_key[idx % 4]; + } + + send_client_message(&mut stream, byte1, &encoded_data, masking_key)?; + } + } else { println!("failed to upgrade connection") } } @@ -95,7 +111,7 @@ pub fn main() -> Result<()> { // function to create a base 64 key and it is done because the server accepts 16 bytes of base 64 encoded key to upgrade the protocol fn generate_base64_key(bytes: u8) -> String { - let mut key_bytes = vec![0u8;bytes as usize]; + let mut key_bytes = vec![0u8; bytes as usize]; rand::rng().fill(&mut key_bytes[..]); diff --git a/ws_core/src/write.rs b/ws_core/src/write.rs index 4d318ef..ff4a674 100644 --- a/ws_core/src/write.rs +++ b/ws_core/src/write.rs @@ -1,7 +1,7 @@ use std::io::{Result, Write}; use std::net::TcpStream; -pub fn send_message(stream: &mut TcpStream, byte1:u8,payload:&[u8]) -> Result<()> { +pub fn send_server_message(stream: &mut TcpStream, byte1:u8,payload:&[u8]) -> Result<()> { let mut frame = Vec::new(); frame.push(byte1); @@ -22,4 +22,34 @@ pub fn send_message(stream: &mut TcpStream, byte1:u8,payload:&[u8]) -> Result<() stream.write_all(&frame) +} + +pub fn send_client_message(stream: &mut TcpStream, byte1:u8,payload:&[u8],masking_key : [u8;4]) -> Result<()> { + let mut frame = Vec::new(); + + frame.push(byte1); + + let mask = 0b1000_0000; + let payload_len = payload.len(); + let byte2 :u8; + + if payload_len <126 { + byte2 = (mask | payload_len) as u8; + frame.push(byte2); + } else if payload_len <= 65535 { + byte2 = (mask | 126) as u8; + frame.push(byte2); + frame.extend_from_slice(&(payload_len as u16).to_be_bytes()); + } else { + byte2 = (mask | 127) as u8; + frame.push(byte2); + frame.extend_from_slice(&(payload_len as u64).to_be_bytes()); + } + + frame.extend_from_slice(&masking_key); + + frame.extend_from_slice(payload); + + stream.write_all(&frame) + } \ No newline at end of file diff --git a/ws_server/src/main.rs b/ws_server/src/main.rs index dc17899..4c48686 100644 --- a/ws_server/src/main.rs +++ b/ws_server/src/main.rs @@ -5,7 +5,7 @@ use std::net::{TcpListener, TcpStream}; use std::thread; use ws_core::read::read_header; -use ws_core::write::send_message; +use ws_core::write::send_server_message; pub fn handle_client(mut stream: TcpStream) -> Result<()> { @@ -82,14 +82,14 @@ pub fn handle_client(mut stream: TcpStream) -> Result<()> { //close frame from the client if cont_opcode == 0b0000_1000 { let byte1 = fin_code | 0b0000_1000; - send_message(&mut stream, byte1, &frame.decoded_data)?; + send_server_message(&mut stream, byte1, &frame.decoded_data)?; return Ok(()); } //ping from the client if cont_opcode == 0b0000_1001 { let byte1 = fin_code | 0b0000_1010; - send_message(&mut stream, byte1, &frame.decoded_data)?; + send_server_message(&mut stream, byte1, &frame.decoded_data)?; continue; } @@ -119,14 +119,14 @@ pub fn handle_client(mut stream: TcpStream) -> Result<()> { println!("Text recieved : {}",text); let byte1 = fin_code | opcode; - send_message(&mut stream, byte1, text.as_bytes())?; + send_server_message(&mut stream, byte1, text.as_bytes())?; continue; } } else { println!("Recieved {} of binary message",final_message.len()); let byte1 = fin_code | opcode; - send_message(&mut stream, byte1, &final_message)?; + send_server_message(&mut stream, byte1, &final_message)?; continue; } }