use std::mem;
use std::net::SocketAddr;
use std::io;
use sys::*;
use net::addr;
pub fn notification_parse(buf: &[u8]) -> io::Result<Option<Notification>> {
let notification: &sctp_notification = unsafe { mem::transmute(buf.as_ptr()) };
let header = unsafe { notification.sn_header };
if header.sn_length as usize != buf.len() {
return Ok(None)
}
let sn_type = match sctp_sn_type::from_u16(header.sn_type) {
Some(sn_type) => sn_type,
None => return Ok(None)
};
match sn_type {
sctp_sn_type::SCTP_SN_TYPE_BASE => {
return Ok(None)
}
sctp_sn_type::SCTP_ASSOC_CHANGE => {
let n = unsafe { notification.sn_assoc_change };
let state = match n.sac_state {
0 => AssocChangeState::CommUp,
1 => AssocChangeState::CommLost,
2 => AssocChangeState::Restart,
3 => AssocChangeState::ShoutdownComp,
4 => AssocChangeState::CantStrAssoc,
_ => AssocChangeState::Unkown
};
let error = notification_error_parse(n.sac_error);
let data_length = n.sac_length as usize - mem::size_of::<u16>() * 6 - mem::size_of::<u32>() - mem::size_of::<i32>();
let data: Vec<u8> = unsafe { n.sac_info.as_slice(data_length).to_vec() };
let assoc_change = AssocChange {
state: state,
error: error,
outbound_streams: n.sac_outbound_streams,
inbound_streams: n.sac_inbound_streams,
assoc_id: n.sac_assoc_id,
data: data
};
return Ok(Some(Notification::AssocChange(assoc_change)))
}
sctp_sn_type::SCTP_PEER_ADDR_CHANGE => {
let n = unsafe { notification.sn_paddr_change };
let addr = addr::sockaddr_to_addr(&n.spc_addr, 128)?;
let state = match n.spc_state {
0 => PaddrChangeState::AddrAvaliable,
1 => PaddrChangeState::AddrUnreachable,
2 => PaddrChangeState::AddrRemove,
3 => PaddrChangeState::AddrAdded,
4 => PaddrChangeState::AddrMadePrim,
5 => PaddrChangeState::AddrConfirmed,
_ => PaddrChangeState::Unkown
};
let error = notification_error_parse(n.spc_error as u16);
let paddr_change = PaddrChange {
addr: addr,
state: state,
error: error,
assoc_id: n.spc_assoc_id
};
return Ok(Some(Notification::PaddrChange(paddr_change)))
}
sctp_sn_type::SCTP_REMOTE_ERROR => {
let n = unsafe { notification.sn_remote_error };
let error = notification_error_parse(n.sre_error);
let data_length = n.sre_length as usize - mem::size_of::<u16>() * 3 - mem::size_of::<u32>() - mem::size_of::<i32>();
let data: Vec<u8> = unsafe { n.sre_data.as_slice(data_length).to_vec() };
let remote_error = RemoteError {
error: error,
assoc_id: n.sre_assoc_id,
data: data
};
return Ok(Some(Notification::RemoteError(remote_error)))
}
sctp_sn_type::SCTP_SEND_FAILED => {
let n = unsafe { notification.sn_send_failed };
let state = match n.ssf_flags {
0 => SendFailedState::DataUnsent,
1 => SendFailedState::DataSent,
_ => SendFailedState::Unkown
};
let error = notification_error_parse(n.ssf_error as u16);
let data_length = n.ssf_length as usize - mem::size_of::<u16>() * 2 - mem::size_of::<u32>() * 2 - mem::size_of::<sctp_sndrcvinfo>() - mem::size_of::<i32>();
let data: Vec<u8> = unsafe { n.ssf_data.as_slice(data_length).to_vec() };
let send_failed = SendFailed {
state: state,
error: error,
info: n.ssf_info,
assoc_id: n.ssf_assoc_id,
data: data
};
return Ok(Some(Notification::SendFailed(send_failed)))
}
sctp_sn_type::SCTP_SHUTDOWN_EVENT => {
let n = unsafe { notification.sn_shutdown_event };
let shutdown = Shutdown {
assoc_id: n.sse_assoc_id
};
return Ok(Some(Notification::Shutdown(shutdown)))
}
sctp_sn_type::SCTP_PARTIAL_DELIVERY_EVENT => {
let n = unsafe { notification.sn_pdapi_event };
let partial_delivery = PartialDelivery {
indication: n.pdapi_indication,
assoc_id: n.pdapi_assoc_id
};
return Ok(Some(Notification::PartialDelivery(partial_delivery)))
}
sctp_sn_type::SCTP_ADAPTATION_INDICATION => {
let n = unsafe { notification.sn_adaptation_event };
let adaptation = Adaptation {
adaptation_ind: n.sai_adaptation_ind,
assoc_id: n.sai_assoc_id
};
return Ok(Some(Notification::Adaptation(adaptation)))
}
sctp_sn_type::SCTP_AUTHENTICATION_INDICATION => {
let n = unsafe { notification.sn_authkey_event };
let authkey = Authkey {
keynumber: n.auth_keynumber,
altkeynumber: n.auth_altkeynumber,
indication: n.auth_indication,
assoc_id: n.auth_assoc_id
};
return Ok(Some(Notification::Authkey(authkey)))
}
sctp_sn_type::SCTP_SENDER_DRY_EVENT => {
let n = unsafe { notification.sn_sender_dry_event };
let sender_dry = SenderDry {
assoc_id: n.sender_dry_assoc_id
};
return Ok(Some(Notification::SenderDry(sender_dry)))
}
}
}
pub fn notification_error_parse(error: u16) -> NotificationError {
match error {
0 => NotificationError::FailedThreshold,
1 => NotificationError::ReceivedSack,
2 => NotificationError::HeartbeatSuccess,
3 => NotificationError::ResponseToUserReq,
4 => NotificationError::InternalError,
5 => NotificationError::ShutdownGuardExpires,
6 => NotificationError::PeerFaulty,
_ => NotificationError::Unkown
}
}
impl sctp_sn_type {
fn from_u16(t: u16) -> Option<sctp_sn_type> {
if sctp_sn_type::SCTP_SN_TYPE_BASE as u16 == t {
return Some(sctp_sn_type::SCTP_SN_TYPE_BASE)
}
if sctp_sn_type::SCTP_ASSOC_CHANGE as u16 == t {
return Some(sctp_sn_type::SCTP_ASSOC_CHANGE)
}
if sctp_sn_type::SCTP_PEER_ADDR_CHANGE as u16 == t {
return Some(sctp_sn_type::SCTP_PEER_ADDR_CHANGE)
}
if sctp_sn_type::SCTP_SEND_FAILED as u16 == t {
return Some(sctp_sn_type::SCTP_SEND_FAILED)
}
if sctp_sn_type::SCTP_REMOTE_ERROR as u16 == t {
return Some(sctp_sn_type::SCTP_REMOTE_ERROR)
}
if sctp_sn_type::SCTP_SHUTDOWN_EVENT as u16 == t {
return Some(sctp_sn_type::SCTP_SHUTDOWN_EVENT)
}
if sctp_sn_type::SCTP_PARTIAL_DELIVERY_EVENT as u16 == t {
return Some(sctp_sn_type::SCTP_PARTIAL_DELIVERY_EVENT)
}
if sctp_sn_type::SCTP_ADAPTATION_INDICATION as u16 == t {
return Some(sctp_sn_type::SCTP_ADAPTATION_INDICATION)
}
if sctp_sn_type::SCTP_AUTHENTICATION_INDICATION as u16 == t {
return Some(sctp_sn_type::SCTP_AUTHENTICATION_INDICATION)
}
if sctp_sn_type::SCTP_SENDER_DRY_EVENT as u16 == t {
return Some(sctp_sn_type::SCTP_SENDER_DRY_EVENT)
}
None
}
}
#[derive(Debug, Clone)]
pub enum Notification {
AssocChange(AssocChange),
PaddrChange(PaddrChange),
RemoteError(RemoteError),
SendFailed(SendFailed),
Shutdown(Shutdown),
Adaptation(Adaptation),
PartialDelivery(PartialDelivery),
Authkey(Authkey),
SenderDry(SenderDry)
}
#[derive(Debug, Clone)]
pub enum NotificationError {
FailedThreshold,
ReceivedSack,
HeartbeatSuccess,
ResponseToUserReq,
InternalError,
ShutdownGuardExpires,
PeerFaulty,
Unkown
}
#[derive(Debug, Clone)]
pub struct AssocChange {
state: AssocChangeState,
error: NotificationError,
outbound_streams: u16,
inbound_streams: u16,
assoc_id: i32,
data: Vec<u8>
}
#[derive(Debug, Clone)]
pub enum AssocChangeState {
CommUp,
CommLost,
Restart,
ShoutdownComp,
CantStrAssoc,
Unkown
}
#[derive(Debug, Clone)]
pub struct PaddrChange {
addr: SocketAddr,
state: PaddrChangeState,
error: NotificationError,
assoc_id: i32,
}
#[derive(Debug, Clone)]
pub enum PaddrChangeState {
AddrAvaliable,
AddrUnreachable,
AddrRemove,
AddrAdded,
AddrMadePrim,
AddrConfirmed,
Unkown
}
#[derive(Debug, Clone)]
pub struct RemoteError {
error: NotificationError,
assoc_id: i32,
data: Vec<u8>
}
#[derive(Debug, Clone)]
pub struct SendFailed {
state: SendFailedState,
error: NotificationError,
info: sctp_sndrcvinfo,
assoc_id: i32,
data: Vec<u8>
}
#[derive(Debug, Clone)]
pub enum SendFailedState {
DataUnsent,
DataSent,
Unkown
}
#[derive(Debug, Clone)]
pub struct Shutdown {
assoc_id: i32
}
#[derive(Debug, Clone)]
pub struct Adaptation {
adaptation_ind: u32,
assoc_id: i32
}
#[derive(Debug, Clone)]
pub struct PartialDelivery {
indication: u32,
assoc_id: i32
}
#[derive(Debug, Clone)]
pub struct Authkey {
keynumber: u16,
altkeynumber: u16,
indication: u32,
assoc_id: i32
}
#[derive(Debug, Clone)]
pub struct SenderDry {
assoc_id: i32
}