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

Support TCP_CONGESTION socket option #370

Closed
BobAnkh opened this issue Dec 24, 2022 · 3 comments · Fixed by #371
Closed

Support TCP_CONGESTION socket option #370

BobAnkh opened this issue Dec 24, 2022 · 3 comments · Fixed by #371

Comments

@BobAnkh
Copy link
Contributor

BobAnkh commented Dec 24, 2022

TCP_CONGESTION is a socket option to choose which tcp congestion control algorithms to use for the socket, which is supported on Linux(since 2.6.13) and FreeBSD(since 9.0).

I wonder would you like to have this socket option in this crate? If so, I would like to contribute this since I have tried to implement it.

While implementing this feature, a string-like(here I choose &str) algorithm name should be passed to the setsockopt function(for example, "reno").
However, while simply convert the name to &[u8] and pass it to the wrapper function setsockopt, the inner calculation of length for this(mem::size_of::<T>) can not have the right value(i.e., true length is 4 while mem::size_of:: gives 16).
Thus, I now implement it with raw syscall! and I wonder if there is a better way to do this?

@Thomasdezeeuw
Copy link
Collaborator

TCP_CONGESTION is a socket option to choose which tcp congestion control algorithms to use for the socket, which is supported on Linux(since 2.6.13) and FreeBSD(since 9.0).

I wonder would you like to have this socket option in this crate? If so, I would like to contribute this since I have tried to implement it.

This addition would be welcome.

While implementing this feature, a string-like(here I choose &str) algorithm name should be passed to the setsockopt function(for example, "reno"). However, while simply convert the name to &[u8] and pass it to the wrapper function setsockopt, the inner calculation of length for this(mem::size_of::<T>) can not have the right value(i.e., true length is 4 while mem::size_of:: gives 16). Thus, I now implement it with raw syscall! and I wonder if there is a better way to do this?

mem::size_of returns the memory size of the a type, in this case &str and &[u8] both are a pointer and a length, so 2 * 8 bytes = 16 bytes on 64 bit. What you're looking for is the length of the string/bytes which you can get by calling .len() on the string/byte slice.

However I don't think you want to use &str or &[u8] but std::ffi::CStr, since C expects a C string (i.e. null terminated).

Also please take a look at our contributing guide, Socket2 has some oddities due to our low level nature.

@BobAnkh
Copy link
Contributor Author

BobAnkh commented Dec 24, 2022

Thank you for your reply, sure I will send a pr when ready.

mem::size_of returns the memory size of the a type, in this case &str and &[u8] both are a pointer and a length, so 2 * 8 bytes = 16 bytes on 64 bit. What you're looking for is the length of the string/bytes which you can get by calling .len() on the string/byte slice.
However I don't think you want to use &str or &[u8] but std::ffi::CStr, since C expects a C string (i.e. null terminated).

What I concerns is that the wrapper provided by socket2 crate itself has the implementation like this:

/// Caller must ensure `T` is the correct type for `opt` and `val`.
pub(crate) unsafe fn setsockopt<T>(fd: Socket, opt: c_int, val: c_int, payload: T,) -> io::Result<()> {
    let payload = ptr::addr_of!(payload).cast();
    syscall!(setsockopt( fd, opt, val, payload, mem::size_of::<T>() as libc::socklen_t,))
    	.map(|_| ())
}

But I have to pass the true length of the string(i.e., CStr or whatever) to the setsockopt which can be acquired by calling .len(). So it seems the wrapper cannot achieve this requirement?

By now, in my experimental implementation, I have to directly call the syscall macro like syscall!(setsockopt( fd, opt, val, payload, len,)).map(|_| ()) in set_tcp_congestion function. Thus I wonder is this accepted or are there other methods to solve it?

@Thomasdezeeuw
Copy link
Collaborator

Thank you for your reply, sure I will send a pr when ready.

mem::size_of returns the memory size of the a type, in this case &str and &[u8] both are a pointer and a length, so 2 * 8 bytes = 16 bytes on 64 bit. What you're looking for is the length of the string/bytes which you can get by calling .len() on the string/byte slice.
However I don't think you want to use &str or &[u8] but std::ffi::CStr, since C expects a C string (i.e. null terminated).

What I concerns is that the wrapper provided by socket2 crate itself has the implementation like this:

/// Caller must ensure `T` is the correct type for `opt` and `val`.
pub(crate) unsafe fn setsockopt<T>(fd: Socket, opt: c_int, val: c_int, payload: T,) -> io::Result<()> {
    let payload = ptr::addr_of!(payload).cast();
    syscall!(setsockopt( fd, opt, val, payload, mem::size_of::<T>() as libc::socklen_t,))
    	.map(|_| ())
}

But I have to pass the true length of the string(i.e., CStr or whatever) to the setsockopt which can be acquired by calling .len(). So it seems the wrapper cannot achieve this requirement?

Correct, the wrapper is for code that mostly uses c_int.

By now, in my experimental implementation, I have to directly call the syscall macro like syscall!(setsockopt( fd, opt, val, payload, len,)).map(|_| ()) in set_tcp_congestion function. Thus I wonder is this accepted or are there other methods to solve it?

Calling it directly is fine. Maybe we can make another version where the length is passed, but that's just the same as use syscall!(setsockopt(...)) directly.

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 a pull request may close this issue.

2 participants