use serde::{Deserialize, Serialize};
pub const MAGIC_BYTES: u16 = 0xDE01;
pub const VERSION: u8 = 1;
pub const FLAG_ENCRYPTED: u8 = 0x01;
pub const FLAG_HANDSHAKE: u8 = 0x02;
pub const FLAG_FILE_CHUNK: u8 = 0x04;
pub const NONCE_LEN: usize = 24;
pub const TAG_LEN: usize = 16;
pub const HEADER_LEN: usize = 2 + 1 + 1 + NONCE_LEN;
#[derive(Serialize, Deserialize, Debug, Clone)]
pub enum ProtocolMessage {
Hello {
public_key: Vec<u8>,
device_id: String,
},
HelloAck {
public_key: Vec<u8>,
},
Resume {
session_id: [u8; 32],
},
ResumeAck,
SwitchToWifi {
ssid: String,
ip: String,
port: u16,
},
FileHeader {
filename: String,
size: u64,
checksum: u32,
},
FileChunk {
offset: u64,
data: Vec<u8>,
},
StreamStart {
name: String,
total_size: Option<u64>,
content_type: Option<String>,
},
StreamChunk {
sequence: u64,
data: Vec<u8>,
},
StreamEnd {
total_bytes: u64,
},
Ack {
id: u64,
},
Ping,
Pong,
}
#[repr(C)]
#[derive(Debug, Clone, Copy)]
pub struct WireHeader {
pub magic: u16,
pub version: u8,
pub flags: u8,
pub nonce: [u8; NONCE_LEN],
}
impl WireHeader {
pub fn to_bytes(&self) -> [u8; HEADER_LEN] {
let mut buf = [0u8; HEADER_LEN];
buf[0..2].copy_from_slice(&self.magic.to_be_bytes());
buf[2] = self.version;
buf[3] = self.flags;
buf[4..4+NONCE_LEN].copy_from_slice(&self.nonce);
buf
}
pub fn from_bytes(buf: &[u8]) -> Option<Self> {
if buf.len() < HEADER_LEN {
return None;
}
let magic = u16::from_be_bytes([buf[0], buf[1]]);
let version = buf[2];
let flags = buf[3];
let mut nonce = [0u8; NONCE_LEN];
nonce.copy_from_slice(&buf[4..4+NONCE_LEN]);
if magic != MAGIC_BYTES {
return None;
}
Some(Self {
magic,
version,
flags,
nonce,
})
}
}