Skip to content

Commit c67c160

Browse files
author
pierresy
committed
Added methods has_nodelay to SctpStream. Also added capability to
change and query send and receive socket buffer. Added connectx methode to SctpStream
1 parent 010acb1 commit c67c160

File tree

3 files changed

+110
-8
lines changed

3 files changed

+110
-8
lines changed

examples/stream.rs

Lines changed: 8 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -9,7 +9,15 @@ fn main() {
99
Err(e) => println!("{:?}", e.kind()),
1010
Ok(mut peer) => {
1111
// Set SCTP no delay
12+
println!("{}", peer.has_nodelay().unwrap());
1213
peer.set_nodelay(true).unwrap();
14+
println!("{}", peer.has_nodelay().unwrap());
15+
16+
// Set socket send buffer size
17+
let oldsize = peer.get_buffer_size(SoBuffer::Send).unwrap();
18+
peer.set_buffer_size(SoBuffer::Send, 4096).unwrap();
19+
println!("Set send buffer size to {} (was : {})", peer.get_buffer_size(SoBuffer::Send).unwrap(), oldsize);
20+
1321
// Write a message using the io::Write trait
1422
peer.write_all("foo bar\n".as_bytes()).unwrap();
1523
// Write a message on stream 6

src/lib.rs

Lines changed: 51 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -3,7 +3,7 @@ extern crate libc;
33

44
mod sctpsock;
55
use sctpsock::{SctpSocket, BindOp, RawSocketAddr};
6-
use sctp_sys::SOCK_SEQPACKET;
6+
use sctp_sys::{SOCK_SEQPACKET, SOL_SCTP};
77

88
use std::io::prelude::*;
99
use std::io::{Result, Error, ErrorKind};
@@ -15,6 +15,20 @@ use std::os::unix::io::{AsRawFd, RawFd, FromRawFd};
1515
use std::os::windows::io::{AsRawHandle, RawHandle, FromRawHandle};
1616

1717

18+
pub enum SoBuffer {
19+
Receive,
20+
Send
21+
}
22+
23+
impl SoBuffer {
24+
fn optname(&self) -> libc::c_int {
25+
return match *self {
26+
SoBuffer::Receive => libc::SO_RCVBUF,
27+
SoBuffer::Send => libc::SO_SNDBUF
28+
};
29+
}
30+
}
31+
1832
/// One-to-one SCTP connected stream which behaves like a TCP stream.
1933
/// A `SctpStream` can be obtained either actively by connecting to a SCTP endpoint with the
2034
/// `connect` constructor, or passively from a `SctpListener` which accepts new connections
@@ -30,6 +44,22 @@ impl SctpStream {
3044
return Ok(SctpStream(sock));
3145
}
3246

47+
/// Create a new stream by connecting it to a remote endpoint
48+
pub fn connectx<A: ToSocketAddrs>(addresses: &[A]) -> Result<SctpStream> {
49+
if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
50+
let mut vec = Vec::with_capacity(addresses.len());
51+
let mut family = libc::AF_INET;
52+
for address in addresses {
53+
let a = try!(SocketAddr::from_addr(address));
54+
if a.family() == libc::AF_INET6 { family = libc::AF_INET6; }
55+
vec.push(a);
56+
}
57+
58+
let sock = try!(SctpSocket::new(family, libc::SOCK_STREAM));
59+
try!(sock.connectx(&vec));
60+
return Ok(SctpStream(sock));
61+
}
62+
3363
/// Send bytes on the specified SCTP stream. On success, returns the
3464
/// quantity of bytes read
3565
pub fn sendmsg(&self, msg: &[u8], stream: u16) -> Result<usize> {
@@ -58,10 +88,28 @@ impl SctpStream {
5888
return self.0.shutdown(how);
5989
}
6090

61-
/// Set or unset SCTP NO DELAY option
91+
/// Set or unset SCTP_NODELAY option
6292
pub fn set_nodelay(&self, nodelay: bool) -> Result<()> {
6393
let val: libc::c_int = if nodelay { 1 } else { 0 };
64-
return self.0.setsockopt(sctp_sys::SCTP_NODELAY, &val);
94+
return self.0.setsockopt(SOL_SCTP, sctp_sys::SCTP_NODELAY, &val);
95+
}
96+
97+
/// Verify if SCTP_NODELAY option is activated for this socket
98+
pub fn has_nodelay(&self) -> Result<bool> {
99+
let val: libc::c_int = try!(self.0.sctp_opt_info(sctp_sys::SCTP_NODELAY, 0));
100+
return Ok(val == 1);
101+
}
102+
103+
/// Set the socket buffer size for the buffer specifid by `buf`.
104+
/// Linux system will double the provided size
105+
pub fn set_buffer_size(&self, buf: SoBuffer, size: usize) -> Result<()> {
106+
return self.0.setsockopt(libc::SOL_SOCKET, buf.optname(), &(size as libc::c_int));
107+
}
108+
109+
/// Get the socket buffer size for the buffer specifid by `buf`
110+
pub fn get_buffer_size(&self, buf: SoBuffer) -> Result<(usize)> {
111+
let val: u32 = try!(self.0.getsockopt(libc::SOL_SOCKET, buf.optname()));
112+
return Ok(val as usize);
65113
}
66114

67115
/// Try to clone the SctpStream. On success, returns a new stream

src/sctpsock.rs

Lines changed: 51 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -40,6 +40,14 @@ fn check_socket(sock: SOCKET) -> Result<SOCKET> {
4040
return Ok(sock);
4141
}
4242

43+
// XXX: Until getsockopt is available in libc crate
44+
extern "system" {
45+
#[cfg(target_os="linux")]
46+
fn getsockopt(sock: SOCKET, level: libc::c_int, optname: libc::c_int, optval: *mut libc::c_void, optlen: *mut libc::socklen_t) -> libc::c_int;
47+
#[cfg(target_os="windows")]
48+
fn getsockopt(sock: SOCKET, level: libc::c_int, optname: libc::c_int, optval: *mut libc::c_char, optlen: *mut libc::c_int) -> libc::c_int;
49+
}
50+
4351
/// SCTP bind operation
4452
#[allow(dead_code)]
4553
pub enum BindOp {
@@ -170,6 +178,33 @@ impl SctpSocket {
170178
}
171179
}
172180

181+
/// Connect the socket to multiple addresses
182+
pub fn connectx<A: ToSocketAddrs>(&self, addresses: &[A]) -> Result<sctp_sys::sctp_assoc_t> {
183+
if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
184+
unsafe {
185+
let buf: *mut u8 = libc::malloc((addresses.len() * size_of::<libc::sockaddr_in6>()) as u64) as *mut u8;
186+
if buf.is_null() {
187+
return Err(Error::new(ErrorKind::Other, "Out of memory"));
188+
}
189+
let mut offset = 0isize;
190+
for address in addresses {
191+
let raw = try!(SocketAddr::from_addr(address));
192+
let len = raw.addr_len();
193+
std::ptr::copy_nonoverlapping(raw.as_ptr() as *mut u8, buf.offset(offset), len as usize);
194+
offset += len as isize;
195+
}
196+
197+
let mut assoc: sctp_sys::sctp_assoc_t = 0;
198+
if sctp_sys::sctp_connectx(self.0, buf as *mut libc::sockaddr, addresses.len() as i32, &mut assoc) != 0 {
199+
let err = Error::last_os_error();
200+
libc::free(buf as *mut libc::c_void);
201+
return Err(err);
202+
}
203+
libc::free(buf as *mut libc::c_void);
204+
return Ok(assoc);
205+
}
206+
}
207+
173208
/// Bind the socket on multiple addresses
174209
pub fn bindx<A: ToSocketAddrs>(&self, addresses: &[A], op: BindOp) -> Result<()> {
175210
if addresses.len() == 0 { return Err(Error::new(ErrorKind::InvalidInput, "No addresses given")); }
@@ -325,18 +360,30 @@ impl SctpSocket {
325360
};
326361
}
327362

328-
/// Set SCTP socket option
329-
pub fn setsockopt<T>(&self, optname: libc::c_int, optval: &T) -> Result<()> {
363+
/// Set socket option
364+
pub fn setsockopt<T>(&self, level: libc::c_int, optname: libc::c_int, optval: &T) -> Result<()> {
330365
unsafe {
331-
return match libc::setsockopt(self.0, sctp_sys::SOL_SCTP, optname, transmute(optval), size_of::<T>() as libc::socklen_t) {
366+
return match libc::setsockopt(self.0, level, optname, transmute(optval), size_of::<T>() as libc::socklen_t) {
332367
0 => Ok(()),
333368
_ => Err(Error::last_os_error())
334369
};
335370
}
336371
}
337372

373+
/// Get socket option
374+
pub fn getsockopt<T>(&self, level: libc::c_int, optname: libc::c_int) -> Result<T> {
375+
unsafe {
376+
let mut val: T = zeroed();
377+
let mut len = size_of::<T>() as libc::socklen_t;
378+
return match getsockopt(self.0, level, optname, transmute(&mut val), &mut len) {
379+
0 => Ok(val),
380+
_ => Err(Error::last_os_error())
381+
};
382+
}
383+
}
384+
338385
/// Get SCTP socket option
339-
pub fn getsockopt<T>(&self, optname: libc::c_int, assoc: sctp_sys::sctp_assoc_t) -> Result<T> {
386+
pub fn sctp_opt_info<T>(&self, optname: libc::c_int, assoc: sctp_sys::sctp_assoc_t) -> Result<T> {
340387
unsafe {
341388
let mut val: T = zeroed();
342389
let mut len = size_of::<T>() as libc::socklen_t;
@@ -347,7 +394,6 @@ impl SctpSocket {
347394
}
348395
}
349396

350-
351397
/// Try to clone this socket
352398
pub fn try_clone(&self) -> Result<SctpSocket> {
353399
unsafe {

0 commit comments

Comments
 (0)