Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

sys::socket listen's Backlog wrapper type addition. #2276

Merged
merged 1 commit into from
Dec 30, 2023

Conversation

devnexen
Copy link
Contributor

changing the sys::socket::listen backlog type from usize to a i32 wrapper, offering known sane values, from -1, SOMAXCONN to
511.

close gh-2264

@devnexen devnexen force-pushed the negative_backlog branch 8 times, most recently from 3e2735c to 6158e15 Compare December 29, 2023 07:32
Copy link
Member

@SteveLauC SteveLauC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks for this PR! I have left some comments. BTW, I would appreciate it if we can have doc comments for these new public types.

A changelog is also needed.

impl Backlog {
/// Sets the listen queue size to system `SOMAXCONN` value
#[cfg(target_os = "redox")]
pub const DEFAULT: Self = Self(128);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Redox has SOMAXCONN defined, we should use it:

$ pwd
/home/steve/Documents/workspace/libcs/libc/src/unix/redox

$ rg "SOMAXCONN"
mod.rs
816:pub const SOMAXCONN: ::c_int = 128;

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

I got an error on CI we might just need to update libc version again (I m the one adding the constant in this crate for redox).

#[cfg(target_os = "redox")]
pub const DEFAULT: Self = Self(128);
#[cfg(not(target_os = "redox"))]
pub const DEFAULT: Self = Self(libc::SOMAXCONN);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Why are we calling this value DEFAULT? But not MAX or simply SOMAXCONN

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

It is mostly what people use we can call it differently sure.

/// Reasonable upper limit, while in theory we might be able
/// to set it to a higher boundary, comes with a risk
/// of resource exhaustion in return
pub const MAXVALUE: Self = Self(511);
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Is it really necessary to expose a MAXVALUE that is specified by us rather than the system?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

We might refine it a bit (e.g. linux/glibc which has SOMAXCONN to 4096, for this case we might go up to 65535).

Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

IMHO, we should not put a restriction that the OS does not have, so I kinda tend to remove this and use SOMAXCONN as the upper bound

fn try_from(backlog: i64) -> std::result::Result<Self, Self::Error> {
match backlog {
..=-2 => Err(BacklogTryFromError::TooNegative),
-1..=511 => Ok(Self(i32::try_from(backlog).map_err(|_| BacklogTryFromError::TooPositive)?)),
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If a backlog of value -1 is only valid on Linux and FreeBSD, why are we allowing it for other OSes here?

Copy link
Contributor Author

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

sure. still a draft :) just wanted first impressions.

@devnexen devnexen force-pushed the negative_backlog branch 3 times, most recently from c34b1d7 to b8630c3 Compare December 29, 2023 15:05
@devnexen devnexen marked this pull request as ready for review December 29, 2023 15:06
Comment on lines 2049 to 2040
impl From<u16> for Backlog {
fn from(backlog: u16) -> Self {
Self(i32::from(backlog))
}
}

impl From<u8> for Backlog {
fn from(backlog: u8) -> Self {
Self(i32::from(backlog))
}
}
Copy link
Member

@SteveLauC SteveLauC Dec 30, 2023

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Just realized that we need to check the value even the value is in range of i32, so what about defining a new(val: i32) function and remove all the helper functions (TryFrom/From) for other types:

/// The `backlog` argument of [`listen()`].
pub struct Backlog(i32);
impl Backlog {
    /// Sets the listen queue size to system `SOMAXCONN` value
    pub const MAXCONN: Backlog = Backlog(libc::SOMAXCONN);
    /// Sets the listen queue size to -1 for system supporting it
    #[cfg(any(target_os = "linux", target_os = "freebsd"))]
    pub const MAXALLOWABLE: Backlog = Backlog(-1);

    /// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid.
    pub fn new(val: i32) -> Result<Self> {
        cfg_if! {
            if #[cfg(any(target_os = "linux", target_os = "freebsd"))] {
                const MIN: i32 = -1;
            } else {
                const MIN: i32 = 0;
            }
        }

        if !(MIN..libc::SOMAXCONN).contains(&val) {
            return Err(Errno::EINVAL);
        }

        Ok(Self(val))
    }
}

If we want to be generic, we can also do new<I: Into<i32>>(val: I).

@devnexen devnexen force-pushed the negative_backlog branch 2 times, most recently from 5064960 to 792b568 Compare December 30, 2023 07:27
pub const MAXALLOWABLE: Self = Self(-1);

// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid.
pub fn new<I: Into<i32> + PartialOrd<I> + From<i32>>(val: I) -> Result<Self> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

If I is Into<i32>, why not just cast it to i32 and do the comparison:

let val = val.into();

And, with this generic function, the other From/TryFrom impls are no longer needed, they are making things overly complicated.

#[cfg(any(target_os = "linux", target_os = "freebsd"))]
pub const MAXALLOWABLE: Self = Self(-1);

// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid.
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Please use a doc comment:

Suggested change
// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid.
/// Create a `Backlog`, an `EINVAL` will be returned if `val` is invalid.

/// Listen for connections on a socket
///
/// [Further reading](https://pubs.opengroup.org/onlinepubs/9699919799/functions/listen.html)
pub fn listen<F: AsFd>(sock: &F, backlog: usize) -> Result<()> {
pub fn listen<F: AsFd, B: Into<Backlog>>(sock: &F, backlog: B) -> Result<()> {
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

With the current impl, we can just use the Backlog type here:

Suggested change
pub fn listen<F: AsFd, B: Into<Backlog>>(sock: &F, backlog: B) -> Result<()> {
pub fn listen<F: AsFd>(sock: &F, backlog: Backlog) -> Result<()> {

let fd = sock.as_fd().as_raw_fd();
let res = unsafe { libc::listen(fd, backlog as c_int) };
let res = unsafe { libc::listen(fd, i32::from(backlog.into())) };
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Backlog is Into<i32>, so we can simply do this:

Suggested change
let res = unsafe { libc::listen(fd, i32::from(backlog.into())) };
let res = unsafe { libc::listen(fd, backlog.into()) };

Comment on lines 1659 to 1660
assert!(Backlog::new(5012).is_err());
assert!(Backlog::new(65535).is_err());
Copy link
Member

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

For these 2 assertions, why not use the libc::SOMAXCONN, like this:

assert!(Backlog::new(libc::SOMAXCONN + 1).is_err());

changing the sys::socket::listen backlog type from `usize` to
a `i32` wrapper, offering known sane values, from -1/0, to SOMAXCONN.

close nix-rustgh-2264
Copy link
Member

@SteveLauC SteveLauC left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Thanks!

@SteveLauC SteveLauC added this pull request to the merge queue Dec 30, 2023
Merged via the queue into nix-rust:master with commit d2445bf Dec 30, 2023
35 checks passed
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

listen does not allow specifying a negative backlog
2 participants