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)
}
}