use crate::client::Client;
use crate::config::Address;
use crate::config::Description;
use crate::constants;
use crate::error::Error;
use crate::messages::Message;
use crate::response::Response;
use crate::write_buffer::WriteBuffer;
const GSO_DONT_CARE: u16 = 0x0001;
const NSI_DISABLE_NA: u8 = 0x04;
const NSI_NA_REQUIRED: u8 = 0x10;
const NSI_SUPPORT_SECURITY_RENEG: u8 = 0x80;
const PROTOCOL_CHARACTERISTICS: u16 = 0x4f98;
const MAX_CONNECT_DATA: usize = 230;
pub struct ConnectMessage<'a> {
pub connect_data: &'a str,
description: &'a Description,
address: &'a Address,
pub sdu: u32,
pub protocol_version: u16,
pub protocol_flags: u32,
pub accepted: bool,
pub tls_renegotiation_needed: bool,
}
impl ConnectMessage<'_> {
pub fn new<'a>(
connect_data: &'a str,
address: &'a Address,
description: &'a Description,
) -> ConnectMessage<'a> {
ConnectMessage {
connect_data,
address,
description,
sdu: description.sdu(),
protocol_version: 0,
protocol_flags: 0,
accepted: false,
tls_renegotiation_needed: false,
}
}
fn process_accept_packet(
&mut self,
resp: &mut Response,
) -> Result<(), Error> {
self.protocol_version = resp.read_u16be()?;
if self.protocol_version < constants::PROTOCOL_VERSION_12 {
return Err(Error::server_version_not_supported());
}
resp.advance(12)?;
let flags1: u8 = resp.read_u8()?;
if flags1 & NSI_NA_REQUIRED != 0 {
todo!();
}
resp.advance(9)?;
self.sdu = resp.read_u32be()?;
if self.protocol_version >= constants::PROTOCOL_VERSION_18 {
resp.advance(5)?;
self.protocol_flags = resp.read_u32be()?;
}
self.accepted = true;
Ok(())
}
fn process_refuse_packet(
&mut self,
resp: &mut Response,
) -> Result<(), Error> {
resp.advance(2)?;
let mut error_num: usize = 0;
let message_len = resp.read_u16be()? as usize;
if message_len > 0 {
let message_bytes = resp.read_bytes(message_len)?;
let message = String::from_utf8(message_bytes.into()).unwrap();
if let Some(start_pos) = message.find("(ERR=")
&& let Some(end_pos) = message[start_pos..].find(")")
{
let error_num_str =
&message[start_pos + 5..start_pos + end_pos];
error_num = error_num_str.parse::<usize>().unwrap();
}
}
let connection_id = self.description.connection_id().to_string();
if error_num == 0 {
Err(Error::unexpected_refuse(connection_id))
} else if error_num == constants::DB_ERR_NUM_INVALID_SERVICE_NAME {
Err(Error::invalid_service_name(
connection_id,
self.description.service_name().to_string(),
self.address.host().to_string(),
self.address.port(),
))
} else if error_num == constants::DB_ERR_NUM_INVALID_SID {
Err(Error::invalid_sid(
connection_id,
self.description.sid().to_string(),
self.address.host().to_string(),
self.address.port(),
))
} else {
Err(Error::listener_refused_connection(
connection_id,
self.address.host().to_string(),
self.address.port(),
error_num,
))
}
}
}
impl Message for ConnectMessage<'_> {
fn deserialize(
&mut self,
_client: &Client,
resp: &mut Response,
) -> Result<(), Error> {
self.accepted = false;
self.tls_renegotiation_needed = false;
match resp.get_packet_type() {
constants::PACKET_TYPE_ACCEPT => {
self.process_accept_packet(resp)?;
}
constants::PACKET_TYPE_REFUSE => {
self.process_refuse_packet(resp)?;
}
constants::PACKET_TYPE_RESEND => {
self.tls_renegotiation_needed = resp.get_packet_flags()
& constants::PACKET_FLAGS_TLS_RENEG
!= 0;
}
_ => {
todo!()
}
}
Ok(())
}
fn extended_data_needed(&self) -> bool {
self.connect_data.len() > MAX_CONNECT_DATA
}
fn get_packet_type(&self) -> u8 {
constants::PACKET_TYPE_CONNECT
}
fn serialize(&self, client: &Client, buf: &mut WriteBuffer) {
let short_sdu: u16 = {
if self.sdu > u16::MAX as u32 {
u16::MAX
} else {
self.sdu.try_into().unwrap()
}
};
let nsi_flags = NSI_SUPPORT_SECURITY_RENEG | NSI_DISABLE_NA;
buf.write_u16be(constants::PROTOCOL_VERSION_23);
buf.write_u16be(constants::PROTOCOL_VERSION_MIN);
buf.write_u16be(GSO_DONT_CARE);
buf.write_u16be(short_sdu);
buf.write_u16be(short_sdu);
buf.write_u16be(PROTOCOL_CHARACTERISTICS);
buf.write_u16be(0); buf.write_u16be(1); buf.write_u16be(self.connect_data.len() as u16);
buf.write_u16be(74); buf.write_u32be(0); buf.write_u8(nsi_flags);
buf.write_u8(nsi_flags);
buf.write_u64be(0); buf.write_u64be(0); buf.write_u64be(0); buf.write_u32be(self.sdu);
buf.write_u32be(self.sdu);
buf.write_u32be(0); buf.write_u32be(0); if !self.extended_data_needed() {
self.serialize_extended_data(client, buf);
}
}
fn serialize_extended_data(
&self,
_client: &Client,
buf: &mut WriteBuffer,
) {
buf.write_bytes(self.connect_data.as_bytes());
}
}