use ytls_traits::ServerHelloProcessor;
use ytls_traits::ServerRecordProcessor;
use super::CipherSuites;
use super::Extensions;
use crate::error::{RecordError, ServerHelloError};
use zerocopy::byteorder::network_endian::U16 as N16;
use zerocopy::{Immutable, IntoBytes, KnownLayout, TryFromBytes, Unaligned};
#[derive(TryFromBytes, IntoBytes, KnownLayout, Immutable, Unaligned)]
#[repr(C)]
#[derive(Debug, PartialEq)]
pub struct ServerHelloHdr {
pub(crate) legacy_version: [u8; 2],
pub(crate) server_random: [u8; 32],
pub(crate) ses_id_len: u8,
}
#[derive(Debug, PartialEq)]
pub struct ServerHello<'r> {
pub(crate) hdr: &'r ServerHelloHdr,
}
impl<'r> ServerHello<'r> {
pub fn parse<P: ServerRecordProcessor>(
prc: &mut P,
bytes: &'r [u8],
) -> Result<(Self, &'r [u8]), RecordError> {
let (hello_hdr, mut rest) = ServerHelloHdr::try_ref_from_prefix(bytes)
.map_err(|e| RecordError::from_zero_copy(e))?;
let sh = prc.server_hello();
sh.handle_server_random(&hello_hdr.server_random);
let ses_id_len: usize = hello_hdr.ses_id_len.into();
if ses_id_len > 32 {
return Err(RecordError::OverflowLength);
}
let ses_id = rest.split_off(..ses_id_len).ok_or(RecordError::Size)?;
sh.handle_session_id(&ses_id);
let cipher_suite = rest.split_off(..2).ok_or(RecordError::Size)?;
sh.handle_selected_cipher_suite([cipher_suite[0], cipher_suite[1]]);
let _compress_method = rest.split_off(..1).ok_or(RecordError::Size)?;
let ext_len_s = rest.split_off(..2).ok_or(RecordError::Size)?;
let extensions_length = u16::from_be_bytes([ext_len_s[0], ext_len_s[1]]);
let extensions = rest
.split_off(..extensions_length as usize)
.ok_or(RecordError::Size)?;
Extensions::parse_server_extensions(prc, extensions)
.map_err(|e| RecordError::ServerHello(ServerHelloError::Extensions(e)))?;
Ok((ServerHello { hdr: hello_hdr }, rest))
}
}