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}