1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219
//! SCTP Socket: An unconnected SCTP Socket
use std::net::SocketAddr;
use std::os::unix::io::RawFd;
use tokio::io::unix::AsyncFd;
use crate::{
AssociationId, BindxFlags, ConnStatus, ConnectedSocket, Event, Listener, SocketToAssociation,
SubscribeEventAssocId,
};
#[allow(unused)]
use super::internal::*;
/// A structure representing an unconnected SCTP Socket.
///
/// When we `listen` on this socket, we get an [`Listener`] on which we can `accept` to
/// get a [`ConnectedSocket`] (This is like `TCPStream` but since this can have multiple
/// associations, we are calling it a 'connected' socket).
pub struct Socket {
inner: AsyncFd<RawFd>,
}
impl Socket {
/// Create a New IPv4 family socket.
///
/// [`SocketToAssociation`] determines the type of the socket created. For a TCP style
/// socket use [`OneToOne`][`SocketToAssociation::OneToOne`] and for a UDP style socket use
/// [`OneToMany`][`SocketToAssociation::OneToMany`]. The socket created is set to a
/// non-blocking socket and is registered for polling for read-write events.
/// For any potentially blocking I/O operations, whether the socket is 'readable' or
/// 'writable' is handled internally.
pub fn new_v4(assoc: SocketToAssociation) -> std::io::Result<Self> {
Ok(Self {
inner: AsyncFd::new(sctp_socket_internal(libc::AF_INET, assoc)?)?,
})
}
/// Create a New IPv6 family socket.
///
/// [`SocketToAssociation`] determines the type of the socket created. For a TCP style
/// socket use [`SocketToAssociation::OneToOne`] and for a UDP style socket use
/// [`SocketToAssociation::OneToMany`]. The socket created is set to a non-blocking
/// socket and is registered for polling for read-write events. For any potentially blocking
/// I/O operations, whether the socket is 'readable' or 'writable' is handled internally.
pub fn new_v6(assoc: SocketToAssociation) -> std::io::Result<Self> {
Ok(Self {
inner: AsyncFd::new(sctp_socket_internal(libc::AF_INET6, assoc)?)?,
})
}
/// Bind a socket to a given IP Address.
///
/// The passed IP address can be an IPv4 or an IPv6, IP address. For the IPv6 family sockets,
/// it is possible to bind to both IPv4 and IPv6 addresses. IPv4 family sockets can be bound
/// only to IPv4 addresses only.
pub fn bind(&self, addr: SocketAddr) -> std::io::Result<()> {
self.sctp_bindx(&[addr], BindxFlags::Add)
}
/// Listen on a given socket.
///
/// This successful operation returns [`Listener`] consuming this structure. The `backlog`
/// parameter determines the length of the listen queue.
pub fn listen(self, backlog: i32) -> std::io::Result<Listener> {
sctp_listen_internal(self.inner, backlog)
}
/// Connect to SCTP Server.
///
/// The successful operation returns [`ConnectedSocket`] consuming this structure.
pub async fn connect(
self,
addr: SocketAddr,
) -> std::io::Result<(ConnectedSocket, AssociationId)> {
sctp_connectx_internal(self.inner, &[addr]).await
}
/// SCTP Specific extension for binding to multiple addresses on a given socket. See Section
/// 9.1 RFC 6458.
///
/// `sctp_bindx` API can be used to add or remove additional addresses to an unbound (ie newly
/// created socket) or a socket that is already bound to address(es) (flag
/// [`Add`][`BindxFlags::Add`]). It is also possible to 'remove' bound addresses from the
/// socket using the same API (flag [`Remove`][`BindxFlags::Remove`]). See the section 9.1
/// for more details about the semantics of which addresses are acceptable for addition or
/// removoal using the `sctp_bindx` API.
pub fn sctp_bindx(&self, addrs: &[SocketAddr], flags: BindxFlags) -> std::io::Result<()> {
sctp_bindx_internal(&self.inner, addrs, flags)
}
/// Connect to a multi-homed Peer. See Section 9.9 RFC 6458
///
/// An Unbound socket when connected to a remote end would return a tuple containing a
/// [connected socket][`ConnectedSocket`] and an [associaton ID][`AssociationId`]. In
/// the case of One-to-many sockets, this association ID can be used for subscribing to SCTP
/// events and requesting additional anciliary control data on the socket.
pub async fn sctp_connectx(
self,
addrs: &[SocketAddr],
) -> std::io::Result<(ConnectedSocket, AssociationId)> {
sctp_connectx_internal(self.inner, addrs).await
}
/// Subscribe to a given SCTP Event on the given socket. See section 6.2.1 of RFC6458.
///
/// SCTP allows receiving notifications about the changes to SCTP associations etc from the
/// user space. For these notification events to be received, this API is used to subsribe for
/// the events while receiving the data on the SCTP Socket.
#[deprecated(since = "0.2.2", note = "use sctp_subscribe_events instead.")]
pub fn sctp_subscribe_event(
&self,
event: Event,
assoc_id: SubscribeEventAssocId,
) -> std::io::Result<()> {
sctp_subscribe_event_internal(&self.inner, event, assoc_id, true)
}
/// Unsubscribe from a given SCTP Event on the given socket. See section 6.2.1 of RFC6458.
///
/// See [`sctp_subscribe_event`][`Self::sctp_subscribe_event`] for further details.
#[deprecated(since = "0.2.2", note = "use sctp_unsubscribe_events instead.")]
pub fn sctp_unsubscribe_event(
&self,
event: Event,
assoc_id: SubscribeEventAssocId,
) -> std::io::Result<()> {
sctp_subscribe_event_internal(&self.inner, event, assoc_id, false)
}
/// Subscribe to SCTP Events. See section 6.2.1 of RFC6458.
///
/// SCTP allows receiving notifications about the changes to SCTP associations etc from the
/// user space. For these notification events to be received, this API is used to subsribe for
/// the events while receiving the data on the SCTP Socket.
pub fn sctp_subscribe_events(
&self,
events: &[Event],
assoc_id: SubscribeEventAssocId,
) -> std::io::Result<()> {
let mut failures = vec![];
for ev in events {
let result = sctp_subscribe_event_internal(&self.inner, ev.clone(), assoc_id, true);
if result.is_err() {
failures.push(result.err().unwrap());
}
}
if failures.is_empty() {
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("{:?}", failures),
))
}
}
/// Unsubscribe from a given SCTP Event on the given socket. See section 6.2.1 of RFC6458.
///
/// See [`sctp_subscribe_events`][`Self::sctp_subscribe_events`] for further details.
pub fn sctp_unsubscribe_events(
&self,
events: &[Event],
assoc_id: SubscribeEventAssocId,
) -> std::io::Result<()> {
let mut failures = vec![];
for ev in events {
let result = sctp_subscribe_event_internal(&self.inner, ev.clone(), assoc_id, false);
if result.is_err() {
failures.push(result.err().unwrap());
}
}
if failures.is_empty() {
Ok(())
} else {
Err(std::io::Error::new(
std::io::ErrorKind::Other,
format!("{:?}", failures),
))
}
}
/// Setup parameters for a new association.
///
/// To specify custom parameters for a new association this API is used.
pub fn sctp_setup_init_params(
&self,
ostreams: u16,
istreams: u16,
retries: u16,
timeout: u16,
) -> std::io::Result<()> {
sctp_setup_init_params_internal(&self.inner, ostreams, istreams, retries, timeout)
}
/// Request to receive `RcvInfo` ancillary data.
///
/// SCTP allows receiving ancillary data about the curent data received on the given socket.
/// This API is used to obtain receive side additional info when the data is to be received.
pub fn sctp_request_rcvinfo(&self, on: bool) -> std::io::Result<()> {
request_rcvinfo_internal(&self.inner, on)
}
/// Request to receive `NxtInfo` ancillary data.
///
/// SCTP allows receiving ancillary data about the curent data received on the given socket.
/// This API is used to obtain information about the next datagram that will be received.
pub fn sctp_request_nxtinfo(&self, on: bool) -> std::io::Result<()> {
request_nxtinfo_internal(&self.inner, on)
}
/// Get the status of the connection associated with the association ID.
pub fn sctp_get_status(&self, assoc_id: AssociationId) -> std::io::Result<ConnStatus> {
sctp_get_status_internal(&self.inner, assoc_id)
}
}