sctp/
lib.rs

1//! This crate provides high level SCTP networking.
2//! Currently it only supports basic SCTP features like multi-homing
3//! in one-to-one and one-to-many associations.
4//! SCTP notifications and working directly on associations is not supported yet
5//! but is in the TODO list.
6
7extern crate libc;
8extern crate sctp_sys;
9extern crate winapi;
10extern crate ws2_32;
11
12mod sctpsock;
13use sctp_sys::{SOCK_SEQPACKET, SOL_SCTP};
14use sctpsock::{BindOp, RawSocketAddr, SctpSocket};
15
16use std::io::prelude::*;
17use std::io::{Error, ErrorKind, Result};
18use std::net::{Shutdown, SocketAddr, ToSocketAddrs};
19
20#[cfg(target_os = "linux")]
21use std::os::unix::io::{AsRawFd, FromRawFd, RawFd};
22
23#[cfg(target_os = "linux")]
24pub mod mio_unix;
25
26#[cfg(target_os = "windows")]
27use std::os::windows::io::{AsRawHandle, FromRawHandle, RawHandle};
28
29#[cfg(target_os = "linux")]
30use libc::{
31    AF_INET, AF_INET6, SOCK_STREAM, SOL_SOCKET, SO_RCVBUF, SO_RCVTIMEO, SO_SNDBUF, SO_SNDTIMEO,
32};
33#[cfg(target_os = "windows")]
34use winapi::{
35    AF_INET, AF_INET6, SOCK_STREAM, SOL_SOCKET, SO_RCVBUF, SO_RCVTIMEO, SO_SNDBUF, SO_SNDTIMEO,
36};
37
38/// Socket direction
39pub enum SoDirection {
40    /// RCV direction
41    Receive,
42    /// SND direction
43    Send,
44}
45
46impl SoDirection {
47    fn buffer_opt(&self) -> libc::c_int {
48        match *self {
49            SoDirection::Receive => SO_RCVBUF,
50            SoDirection::Send => SO_SNDBUF,
51        }
52    }
53
54    fn timeout_opt(&self) -> libc::c_int {
55        match *self {
56            SoDirection::Receive => SO_RCVTIMEO,
57            SoDirection::Send => SO_SNDTIMEO,
58        }
59    }
60}
61
62/// One-to-one SCTP connected stream which behaves like a TCP stream.
63/// A `SctpStream` can be obtained either actively by connecting to a SCTP endpoint with the
64/// `connect` constructor, or passively from a `SctpListener` which accepts new connections
65pub struct SctpStream(SctpSocket);
66
67impl SctpStream {
68    /// Create a new stream by connecting it to a remote endpoint
69    pub fn connect<A: ToSocketAddrs>(address: A) -> Result<SctpStream> {
70        let raw_addr = SocketAddr::from_addr(&address)?;
71        let sock = SctpSocket::new(raw_addr.family(), SOCK_STREAM)?;
72        sock.connect(raw_addr)?;
73        Ok(SctpStream(sock))
74    }
75
76    /// Create a new stream by connecting it to a remote endpoint having multiple addresses
77    pub fn connectx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpStream> {
78        if addresses.is_empty() {
79            return Err(Error::new(ErrorKind::InvalidInput, "No addresses given"));
80        }
81        let mut vec = Vec::with_capacity(addresses.len());
82        let mut family = AF_INET;
83        for address in addresses {
84            let a = SocketAddr::from_addr(address)?;
85            if a.family() == AF_INET6 {
86                family = AF_INET6;
87            }
88            vec.push(a);
89        }
90
91        let sock = SctpSocket::new(family, SOCK_STREAM)?;
92        sock.connectx(&vec)?;
93        Ok(SctpStream(sock))
94    }
95
96    /// Send bytes on the specified SCTP stream. On success, returns the
97    /// quantity of bytes read
98    pub fn sendmsg(&self, msg: &[u8], stream: u16) -> Result<usize> {
99        self.0.sendmsg::<SocketAddr>(msg, None, 0, stream, 0)
100    }
101
102    /// Send bytes on the specified SCTP stream. On success, returns the
103    /// quantity of bytes read
104    pub fn sendmsg_ppid(&self, msg: &[u8], ppid: u32, stream: u16) -> Result<usize> {
105        self.0.sendmsg::<SocketAddr>(msg, None, ppid, stream, 0)
106    }
107
108    /// Read bytes. On success, return a tuple with the quantity of
109    /// bytes received and the stream they were recived on
110    pub fn recvmsg(&self, msg: &mut [u8]) -> Result<(usize, u16)> {
111        let (size, stream, _) = self.0.recvmsg(msg)?;
112        Ok((size, stream))
113    }
114
115    /// Return the list of local socket addresses for this stream
116    pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
117        self.0.local_addrs(0)
118    }
119
120    /// Return the list of socket addresses for the peer this stream is connected to
121    pub fn peer_addrs(&self) -> Result<Vec<SocketAddr>> {
122        self.0.peer_addrs(0)
123    }
124
125    /// Shuts down the read, write, or both halves of this connection
126    pub fn shutdown(&self, how: Shutdown) -> Result<()> {
127        self.0.shutdown(how)
128    }
129
130    /// Set or unset SCTP_NODELAY option
131    pub fn set_nodelay(&self, nodelay: bool) -> Result<()> {
132        let val: libc::c_int = if nodelay { 1 } else { 0 };
133        self.0.setsockopt(SOL_SCTP, sctp_sys::SCTP_NODELAY, &val)
134    }
135
136    /// Verify if SCTP_NODELAY option is activated for this socket
137    pub fn has_nodelay(&self) -> Result<bool> {
138        let val: libc::c_int = self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0)?;
139        Ok(val == 1)
140    }
141
142    /// Set the socket buffer size for the direction specified by `dir`.
143    /// Linux systems will double the provided size
144    pub fn set_buffer_size(&self, dir: SoDirection, size: usize) -> Result<()> {
145        self.0
146            .setsockopt(SOL_SOCKET, dir.buffer_opt(), &(size as libc::c_int))
147    }
148
149    /// Get the socket buffer size for the direction specified by `dir`
150    pub fn get_buffer_size(&self, dir: SoDirection) -> Result<usize> {
151        let val: u32 = self.0.getsockopt(SOL_SOCKET, dir.buffer_opt())?;
152        Ok(val as usize)
153    }
154
155    /// Set `timeout` in seconds for operation `dir` (either receive or send)
156    pub fn set_timeout(&self, dir: SoDirection, timeout: i32) -> Result<()> {
157        // Workaround: Use of long instead of libc::time_t which does not compile in windows x86_64
158        let tval = libc::timeval {
159            tv_sec: timeout as libc::c_long,
160            tv_usec: 0,
161        };
162        self.0.setsockopt(SOL_SOCKET, dir.timeout_opt(), &tval)
163    }
164
165    /// Try to clone the SctpStream. On success, returns a new stream
166    /// wrapping a new socket handler
167    pub fn try_clone(&self) -> Result<SctpStream> {
168        Ok(SctpStream(self.0.try_clone()?))
169    }
170}
171
172impl Read for SctpStream {
173    fn read(&mut self, buf: &mut [u8]) -> Result<usize> {
174        self.0.recv(buf)
175    }
176}
177
178impl Write for SctpStream {
179    fn write(&mut self, buf: &[u8]) -> Result<usize> {
180        self.0.send(buf)
181    }
182
183    fn flush(&mut self) -> Result<()> {
184        Ok(())
185    }
186}
187
188#[cfg(target_os = "windows")]
189impl AsRawHandle for SctpStream {
190    fn as_raw_handle(&self) -> RawHandle {
191        return self.0.as_raw_handle();
192    }
193}
194
195#[cfg(target_os = "windows")]
196impl FromRawHandle for SctpStream {
197    unsafe fn from_raw_handle(hdl: RawHandle) -> SctpStream {
198        SctpStream(SctpSocket::from_raw_handle(hdl))
199    }
200}
201
202#[cfg(target_os = "linux")]
203impl AsRawFd for SctpStream {
204    fn as_raw_fd(&self) -> RawFd {
205        self.0.as_raw_fd()
206    }
207}
208
209#[cfg(target_os = "linux")]
210impl FromRawFd for SctpStream {
211    unsafe fn from_raw_fd(fd: RawFd) -> SctpStream {
212        SctpStream(SctpSocket::from_raw_fd(fd))
213    }
214}
215
216/// One-to-many SCTP endpoint.
217pub struct SctpEndpoint(SctpSocket);
218
219impl SctpEndpoint {
220    /// Create a one-to-many SCTP endpoint bound to a single address
221    pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpEndpoint> {
222        let raw_addr = SocketAddr::from_addr(&address)?;
223        let sock = SctpSocket::new(raw_addr.family(), SOCK_SEQPACKET)?;
224        sock.bind(raw_addr)?;
225        sock.listen(-1)?;
226        Ok(SctpEndpoint(sock))
227    }
228
229    /// Create a one-to-many SCTP endpoint bound to a multiple addresses. Requires at least one address
230    pub fn bindx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpEndpoint> {
231        if addresses.is_empty() {
232            return Err(Error::new(ErrorKind::InvalidInput, "No addresses given"));
233        }
234        let mut vec = Vec::with_capacity(addresses.len());
235        let mut family = AF_INET;
236        for address in addresses {
237            let a = SocketAddr::from_addr(address)?;
238            if a.family() == AF_INET6 {
239                family = AF_INET6;
240            }
241            vec.push(a);
242        }
243
244        let sock = SctpSocket::new(family, SOCK_SEQPACKET)?;
245        sock.bindx(&vec, BindOp::AddAddr)?;
246        sock.listen(-1)?;
247        Ok(SctpEndpoint(sock))
248    }
249
250    /// Wait for data to be received. On success, returns a triplet containing
251    /// the quantity of bytes received, the sctp stream id on which data were received, and
252    /// the socket address used by the peer to send the data
253    pub fn recv_from(&self, msg: &mut [u8]) -> Result<(usize, u16, SocketAddr)> {
254        self.0.recvmsg(msg)
255    }
256
257    /// Send data in Sctp style, to the provided address on the stream `stream`.
258    /// On success, returns the quantity on bytes sent
259    pub fn send_to<A: ToSocketAddrs>(
260        &self,
261        msg: &mut [u8],
262        address: A,
263        stream: u16,
264    ) -> Result<usize> {
265        self.0.sendmsg(msg, Some(address), 0, stream, 0)
266    }
267
268    /// Get local socket addresses to which this socket is bound
269    pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
270        self.0.local_addrs(0)
271    }
272
273    /// Shuts down the read, write, or both halves of this connection
274    pub fn shutdown(&self, how: Shutdown) -> Result<()> {
275        self.0.shutdown(how)
276    }
277
278    /// Set or unset SCTP_NODELAY option
279    pub fn set_nodelay(&self, nodelay: bool) -> Result<()> {
280        let val: libc::c_int = if nodelay { 1 } else { 0 };
281        self.0.setsockopt(SOL_SCTP, sctp_sys::SCTP_NODELAY, &val)
282    }
283
284    /// Verify if SCTP_NODELAY option is activated for this socket
285    pub fn has_nodelay(&self) -> Result<bool> {
286        let val: libc::c_int = self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0)?;
287        Ok(val == 1)
288    }
289
290    /// Set the socket buffer size for the direction specified by `dir`.
291    /// Linux systems will double the provided size
292    pub fn set_buffer_size(&self, dir: SoDirection, size: usize) -> Result<()> {
293        self.0
294            .setsockopt(SOL_SOCKET, dir.buffer_opt(), &(size as libc::c_int))
295    }
296
297    /// Get the socket buffer size for the direction specified by `dir`
298    pub fn get_buffer_size(&self, dir: SoDirection) -> Result<usize> {
299        let val: u32 = self.0.getsockopt(SOL_SOCKET, dir.buffer_opt())?;
300        Ok(val as usize)
301    }
302
303    /// Set `timeout` in seconds for operation `dir` (either receive or send)
304    pub fn set_timeout(&self, dir: SoDirection, timeout: i32) -> Result<()> {
305        // Workaround: Use of long instead of libc::time_t which does not compile in windows x86_64
306        let tval = libc::timeval {
307            tv_sec: timeout as libc::c_long,
308            tv_usec: 0,
309        };
310        self.0.setsockopt(SOL_SOCKET, dir.timeout_opt(), &tval)
311    }
312
313    /// Try to clone this socket
314    pub fn try_clone(&self) -> Result<SctpEndpoint> {
315        Ok(SctpEndpoint(self.0.try_clone()?))
316    }
317}
318
319#[cfg(target_os = "windows")]
320impl AsRawHandle for SctpEndpoint {
321    fn as_raw_handle(&self) -> RawHandle {
322        return self.0.as_raw_handle();
323    }
324}
325
326#[cfg(target_os = "windows")]
327impl FromRawHandle for SctpEndpoint {
328    unsafe fn from_raw_handle(hdl: RawHandle) -> SctpEndpoint {
329        SctpEndpoint(SctpSocket::from_raw_handle(hdl))
330    }
331}
332
333#[cfg(target_os = "linux")]
334impl AsRawFd for SctpEndpoint {
335    fn as_raw_fd(&self) -> RawFd {
336        self.0.as_raw_fd()
337    }
338}
339
340#[cfg(target_os = "linux")]
341impl FromRawFd for SctpEndpoint {
342    unsafe fn from_raw_fd(fd: RawFd) -> SctpEndpoint {
343        SctpEndpoint(SctpSocket::from_raw_fd(fd))
344    }
345}
346
347/// Iterator over incoming connections on `SctpListener`
348pub struct Incoming<'a>(&'a SctpListener);
349
350impl<'a> std::iter::Iterator for Incoming<'a> {
351    type Item = Result<SctpStream>;
352
353    fn next(&mut self) -> Option<Result<SctpStream>> {
354        match self.0.accept() {
355            Ok((stream, _)) => Some(Ok(stream)),
356            Err(e) => Some(Err(e)),
357        }
358    }
359}
360
361/// SCTP listener which behaves like a `TcpListener`.
362/// A SCTP listener is used to wait for and accept one-to-one SCTP connections.
363/// An accepted connection is represented by `SctpStream`.
364pub struct SctpListener(SctpSocket);
365
366impl SctpListener {
367    /// Create a listener bound to a single address
368    pub fn bind<A: ToSocketAddrs>(address: A) -> Result<SctpListener> {
369        let raw_addr = SocketAddr::from_addr(&address)?;
370        let sock = SctpSocket::new(raw_addr.family(), SOCK_STREAM)?;
371        sock.bind(raw_addr)?;
372        sock.listen(-1)?;
373        Ok(SctpListener(sock))
374    }
375
376    /// Create a listener bound to multiple addresses. Requires at least one address
377    pub fn bindx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpListener> {
378        if addresses.is_empty() {
379            return Err(Error::new(ErrorKind::InvalidInput, "No addresses given"));
380        }
381        let mut vec = Vec::with_capacity(addresses.len());
382        let mut family = AF_INET;
383        for address in addresses {
384            let a = SocketAddr::from_addr(address)?;
385            if a.family() == AF_INET6 {
386                family = AF_INET6;
387            }
388            vec.push(a);
389        }
390
391        let sock = SctpSocket::new(family, SOCK_STREAM)?;
392        sock.bindx(&vec, BindOp::AddAddr)?;
393        sock.listen(-1)?;
394        Ok(SctpListener(sock))
395    }
396
397    /// Accept a new connection
398    pub fn accept(&self) -> Result<(SctpStream, SocketAddr)> {
399        let (sock, addr) = self.0.accept()?;
400        Ok((SctpStream(sock), addr))
401    }
402
403    /// Iterate over new connections
404    pub fn incoming(&self) -> Incoming {
405        Incoming(self)
406    }
407
408    /// Get the listener local addresses
409    pub fn local_addrs(&self) -> Result<Vec<SocketAddr>> {
410        self.0.local_addrs(0)
411    }
412
413    /// Set `timeout` in seconds on accept
414    pub fn set_timeout(&self, timeout: i32) -> Result<()> {
415        // Workaround: Use of long instead of libc::time_t which does not compile in windows x86_64
416        let tval = libc::timeval {
417            tv_sec: timeout as libc::c_long,
418            tv_usec: 0,
419        };
420        self.0.setsockopt(SOL_SOCKET, SO_RCVTIMEO, &tval)
421    }
422
423    /// Try to clone this listener
424    pub fn try_clone(&self) -> Result<SctpListener> {
425        Ok(SctpListener(self.0.try_clone()?))
426    }
427}
428
429#[cfg(target_os = "windows")]
430impl AsRawHandle for SctpListener {
431    fn as_raw_handle(&self) -> RawHandle {
432        self.0.as_raw_handle()
433    }
434}
435
436#[cfg(target_os = "windows")]
437impl FromRawHandle for SctpListener {
438    unsafe fn from_raw_handle(hdl: RawHandle) -> SctpListener {
439        SctpListener(SctpSocket::from_raw_handle(hdl))
440    }
441}
442
443#[cfg(target_os = "linux")]
444impl AsRawFd for SctpListener {
445    fn as_raw_fd(&self) -> RawFd {
446        self.0.as_raw_fd()
447    }
448}
449
450#[cfg(target_os = "linux")]
451impl FromRawFd for SctpListener {
452    unsafe fn from_raw_fd(fd: RawFd) -> SctpListener {
453        SctpListener(SctpSocket::from_raw_fd(fd))
454    }
455}