huron huron - 28 days ago 8
Linux Question

How to set the socket option SO_REUSEPORT in Rust?

I've read the documentation for

std::net
and mio, and I've found some methods like
set_nodelay
and
set_keepalive
, but I haven't found a way to set other socket options like
SO_REUSEPORT
and
SO_REUSEADDR
on a given socket. How can I do this?

Answer

Because SO_REUSEPORT isn't cross-platform, you will need to dip into platform-specific code. In this case, you can get the raw file descriptor from the socket and then use functions, types, and values from the libc crate to set the options you want:

extern crate libc;

use std::net::TcpListener;
use std::os::unix::io::AsRawFd;
use std::{io, mem};

fn main() {
    let listener = TcpListener::bind("0.0.0.0:8888").expect("Unable to bind");

    unsafe {
        let optval: libc::c_int = 1;
        let ret = libc::setsockopt(listener.as_raw_fd(),
                                   libc::SOL_SOCKET,
                                   libc::SO_REUSEPORT,
                                   &optval as *const _ as *const libc::c_void,
                                   mem::size_of_val(&optval) as libc::socklen_t);
        if ret != 0 {
            let err: Result<(), _> = Err(io::Error::last_os_error());
            err.expect("setsockopt failed");
        }
    }

    println!("Hello, world!");
}

I make no guarantee that this is the right place to set this option, or that I haven't screwed up something in the unsafe block, but it does compile and run on macOS 10.12.

An even better solution may be to check out the nix crate, which provides nicer wrappers for most *nix-specific code:

extern crate nix;

use std::net::TcpListener;
use std::os::unix::io::AsRawFd;
use nix::sys::socket;
use nix::sys::socket::sockopt::ReusePort;

fn main() {
    let listener = TcpListener::bind("0.0.0.0:8888").expect("Unable to bind");
    socket::setsockopt(listener.as_raw_fd(), ReusePort, &true).expect("setsockopt failed");

    println!("Hello, world!");
}
Comments