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
//! Listening SCTP Socket

use std::net::SocketAddr;
use std::os::unix::io::RawFd;

use tokio::io::unix::AsyncFd;

#[allow(unused)]
use crate::internal::*;
use crate::{
    types::AssociationId, BindxFlags, ConnStatus, ConnectedSocket, Event, NotificationOrData,
    SendData, SubscribeEventAssocId,
};

/// A structure representing a socket that is listening for incoming SCTP Connections.
///
/// This structure is created by an [`Socket`][crate::Socket] when it is bound to local address(es)
/// and is waiting for incoming connections by calling the `listen` on the socket. The original
/// [`Socket`][crate::Socket] is consumed when this structure is created. See
/// [`Socket::listen`][crate::Socket::listen] for more details.
pub struct Listener {
    inner: AsyncFd<RawFd>,
}

impl Listener {
    /// Accept on a given socket (valid only for `OneToOne` type sockets).
    pub async fn accept(&self) -> std::io::Result<(ConnectedSocket, SocketAddr)> {
        accept_internal(&self.inner).await
    }

    /// Shutdown on the socket
    pub fn shutdown(&self, how: std::net::Shutdown) -> std::io::Result<()> {
        shutdown_internal(&self.inner, how)
    }

    /// Binds to one or more local addresses. See: Section 9.1 RFC 6458
    ///
    /// It is possible to call `sctp_bindx` on an already 'bound' (that is 'listen'ing socket.)
    pub fn sctp_bindx(&self, addrs: &[SocketAddr], flags: BindxFlags) -> std::io::Result<()> {
        sctp_bindx_internal(&self.inner, addrs, flags)
    }

    /// Peels off a connected SCTP association from the listening socket. See: Section 9.2 RFC 6458
    ///
    /// This call is successful only for UDP style one to many sockets. This is like
    /// `[Listener::accept`] where peeled off socket behaves like a stand alone
    /// one-to-one socket.
    pub fn sctp_peeloff(&self, assoc_id: AssociationId) -> std::io::Result<ConnectedSocket> {
        sctp_peeloff_internal(&self.inner, assoc_id)
    }

    /// Get Peer Address(es) for the given Association ID. See: Section 9.3 RFC 6458
    ///
    /// This function is supported on the [`Listener`] because in the case of One to Many
    /// associations that are not peeled off, we are performing IO operations on the listening
    /// socket itself.
    pub fn sctp_getpaddrs(&self, assoc_id: AssociationId) -> std::io::Result<Vec<SocketAddr>> {
        sctp_getpaddrs_internal(&self.inner, assoc_id)
    }

    /// Get's the Local Addresses for the association. See: Section 9.4 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 listening socket.
    ///
    /// In the case of One-to-many sockets, it is possible to receive on the listening socket,
    /// without explicitly 'accept'ing or 'peeling off' the 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, to: SocketAddr, data: SendData) -> std::io::Result<()> {
        sctp_sendmsg_internal(&self.inner, Some(to), 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),
            ))
        }
    }

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

    // functions not part of public APIs
    pub(crate) fn from_rawfd(fd: RawFd) -> std::io::Result<Self> {
        Ok(Self {
            inner: AsyncFd::new(fd)?,
        })
    }
}

impl Drop for Listener {
    // Drop for `Listener`. We close the `inner` RawFd
    fn drop(&mut self) {
        close_internal(&self.inner);
    }
}