///|
fn[T] from_sctp(
operation : () -> T raise @sctp.SctpError,
) -> T raise DataChannelError {
operation() catch {
error => raise Sctp(error)
}
}
///|
pub struct Transport {
association : @sctp.Association
manager : Manager
}
///|
pub fn Transport::new(
role~ : StreamRole,
association_config~ : @sctp.AssociationConfig,
) -> Transport raise DataChannelError {
Transport::with_manager(manager=Manager::new(role~), association_config~)
}
///|
pub fn Transport::with_manager(
manager~ : Manager,
association_config~ : @sctp.AssociationConfig,
) -> Transport raise DataChannelError {
let role = manager.role()
let expected_role : @sctp.AssociationRole = if role == DtlsClient {
Active
} else {
Passive
}
if association_config.role() != expected_role {
raise InvalidConfiguration(
"SCTP association role does not match the DTLS stream-id role",
)
}
{
association: from_sctp(() => @sctp.Association::new(association_config)),
manager,
}
}
///|
fn Transport::pump(
self : Transport,
now : @transport.Instant,
) -> Unit raise DataChannelError {
while self.association.poll_event() is Some(event) {
self.manager.handle_sctp_event(event)
}
while self.manager.poll_command() is Some(command) {
match command {
SendSctp(message, reliability) =>
from_sctp(() => self.association.send(message, reliability~, now~))
ResetSctpStream(stream) =>
from_sctp(() => self.association.reset_stream(stream, now))
}
}
}
///|
pub fn Transport::start(
self : Transport,
now : @transport.Instant,
) -> Unit raise DataChannelError {
from_sctp(() => self.association.start(now))
self.pump(now)
}
///|
pub fn Transport::handle_datagram(
self : Transport,
now : @transport.Instant,
datagram : Bytes,
) -> Unit raise DataChannelError {
from_sctp(() => self.association.handle_datagram(now, datagram))
self.pump(now)
}
///|
pub fn Transport::poll_datagram(self : Transport) -> Bytes? {
self.association.poll_datagram()
}
///|
pub fn Transport::create_channel(
self : Transport,
config : DataChannelConfig,
now : @transport.Instant,
) -> DataChannel raise DataChannelError {
let channel = self.manager.create_channel(config)
self.pump(now)
channel
}
///|
pub fn Transport::channel(
self : Transport,
stream : @sctp.StreamId,
) -> DataChannel? {
self.manager.channel(stream)
}
///|
pub fn Transport::send(
self : Transport,
stream : @sctp.StreamId,
message : DataChannelMessage,
now : @transport.Instant,
) -> Unit raise DataChannelError {
self.manager.send(stream, message)
self.pump(now)
}
///|
pub fn Transport::close_channel(
self : Transport,
stream : @sctp.StreamId,
now : @transport.Instant,
) -> Unit raise DataChannelError {
self.manager.close_channel(stream)
self.pump(now)
}
///|
pub fn Transport::buffered_amount(
self : Transport,
stream : @sctp.StreamId,
) -> UInt64 {
self.association.buffered_amount(stream)
}
///|
pub fn Transport::set_buffered_amount_low_threshold(
self : Transport,
stream : @sctp.StreamId,
threshold : UInt64,
) -> Unit {
self.association.set_buffered_amount_low_threshold(stream, threshold)
}
///|
pub fn Transport::poll_event(self : Transport) -> DataChannelEvent? {
self.manager.poll_event()
}
///|
pub fn Transport::poll_timeout(self : Transport) -> @transport.Instant? {
self.association.poll_timeout()
}
///|
pub fn Transport::handle_timeout(
self : Transport,
now : @transport.Instant,
) -> Unit raise DataChannelError {
from_sctp(() => self.association.handle_timeout(now))
self.pump(now)
}
///|
pub fn Transport::close(
self : Transport,
now : @transport.Instant,
) -> Unit raise DataChannelError {
from_sctp(() => self.association.close(now))
self.pump(now)
}
///|
pub fn Transport::association_state(self : Transport) -> @sctp.AssociationState {
self.association.state()
}