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
//! A Connected SCTP Socket. This is similar to `TCPStream`.
use tokio::io::unix::AsyncFd;
use std::net::SocketAddr;
use std::os::unix::io::RawFd;
#[allow(unused)]
use crate::internal::*;
use crate::{
AssociationId, BindxFlags, ConnStatus, Event, NotificationOrData, SendData, SendInfo,
SubscribeEventAssocId,
};
/// A structure representing a Connected SCTP socket.
///
/// A Connected SCTP Socket is associated with one or more Peer associations (each of which is
/// identified by an Association ID). A Connected SCTP Socket will be created by an
/// [`Listener`][crate::Listener] when it calls an `accept` (in the case of One to One style
/// sockets) or upon receiving a `SCTP_COMM_UP` event in `SCTP_ASSOC_CHANGE` notification.
///
/// It is also possible to [`peeloff`][crate::Listener::sctp_peeloff] a socket from One to Many
/// listening socket and the peeled socket is an [`ConnectedSocket`].
#[derive(Debug)]
pub struct ConnectedSocket {
inner: AsyncFd<RawFd>,
}
impl ConnectedSocket {
/// Creates new [`ConnectedSocket`] from a [`RawFd`][std::os::unix::io::RawFd].
///
/// TODO: Remove this from Public API
/// Although, this is available as public API as of now, likely the users are not required to
/// use this. Mostly [`accept`][`crate::Listener::accept`] (in the case of One to One
/// Socket to Association) or [`peeloff`][`crate::Listener::sctp_peeloff`] (in the case of
/// One to Many Association) would use this API to create new [`ConnectedSocket`].
pub fn from_rawfd(rawfd: RawFd) -> std::io::Result<Self> {
Ok(Self {
inner: AsyncFd::new(rawfd)?,
})
}
/// Perform a TCP like half close.
///
/// Note: however that the semantics for TCP and SCTP half close are different. See section
/// 4.1.7 of RFC 6458 for details.
pub fn shutdown(&self, how: std::net::Shutdown) -> std::io::Result<()> {
shutdown_internal(&self.inner, how)
}
/// Bind to addresses on the given socket. See Section 9.1 RFC 6458.
///
/// For the connected sockets, this feature is optional and hence will *always* return
/// `ENOTSUP(EOPNOTSUP)` error.
pub fn sctp_bindx(&self, _addrs: &[SocketAddr], _flags: BindxFlags) -> std::io::Result<()> {
Err(std::io::Error::from_raw_os_error(95))
}
/// Get Peer addresses for the association. See Section 9.3 RFC 6458.
pub fn sctp_getpaddrs(&self, assoc_id: AssociationId) -> std::io::Result<Vec<SocketAddr>> {
sctp_getpaddrs_internal(&self.inner, assoc_id)
}
/// Get Local addresses for the association. See section 9.5 RFC 6458.
pub fn sctp_getladdrs(&self, assoc_id: AssociationId) -> std::io::Result<Vec<SocketAddr>> {
sctp_getladdrs_internal(&self.inner, assoc_id)
}
/// Receive Data or Notification from the connected socket.
///
/// The internal API used to receive the data is also the API used to receive notifications.
/// This function returns either the notification (which the user should have subscribed for)
/// or the data.
pub async fn sctp_recv(&self) -> std::io::Result<NotificationOrData> {
sctp_recvmsg_internal(&self.inner).await
}
/// Send Data and Anciliary data if any on the SCTP Socket.
///
/// SCTP supports sending the actual SCTP message together with sending any anciliary data on
/// the SCTP association. The anciliary data is optional.
pub async fn sctp_send(&self, data: SendData) -> std::io::Result<()> {
sctp_sendmsg_internal(&self.inner, None, data).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),
))
}
}
/// 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)
}
/// Set Default `SendInfo` values for this socket.
///
/// In the [`sctp_send`] API, an optional `SendInfo` is present, which can be used to specify the
/// ancillary data along with the payload. Instead, a sender can chose to use this API to set
/// the default `SendInfo` to be used while sending the data for this 'connected' socket.
/// Note: This API is provided only for the [`ConnectedSocket`].
pub fn sctp_set_default_sendinfo(&self, sendinfo: SendInfo) -> std::io::Result<()> {
sctp_set_default_sendinfo_internal(&self.inner, sendinfo)
}
}
impl Drop for ConnectedSocket {
// Drop for `ConnectedSocket`. We close the `inner` RawFd
fn drop(&mut self) {
close_internal(&self.inner);
}
}