sctp_rs/
socket.rs

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