-
Notifications
You must be signed in to change notification settings - Fork 175
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
Add trait to reduce duplicated code between socket address types, implement netlink addresses #1004
base: main
Are you sure you want to change the base?
Conversation
f694272
to
4c1c746
Compare
As a quick update here, I am looking forward to reviewing this; I've just been busy. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
I like this approach, it allows me to very easily define a socket address not yet present in this crate, like so
#[derive(Debug, Clone, Copy)]
#[allow(dead_code)] // fields are never read directly because they get memcp'd into another struct
#[repr(C)]
struct SocketAddressHci {
hci_family: rustix::net::AddressFamily,
hci_dev: u16,
hci_channel: u16,
}
unsafe impl SocketAddress for SocketAddressHci {
/// SAFETY: `SocketAddressHci` has the same layout as the type in the kernel and can therefore safely be passed in a syscall
type CSockAddr = Self;
fn encode(&self) -> Self::CSockAddr {
self.clone()
}
}
I left some comment about the code structure, most of it more nit than anything else. I am interested to here your opinion on using something like a Bow
for the return value of encode
tho. It would allow impl's to avoid the clone without having to reimplement write_sockaddr
and with_sockaddr
again :)
4c1c746
to
013792a
Compare
44051ea
to
9b432db
Compare
Given that I also rebased to clean up the messy history for easier review. Full history archived here. |
Hi, any updates on this PR? Looking forward |
This would be very nice to have in 1.0 |
Thanks for the pings here, and your patience! I'll make an effort to review this before 1.0. |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This looks really nice!
I was initially worried about the safety of the f
called by the with_sockaddr
function, however I now see that the safety requirements are covered by the pub unsafe trait
, so it looks good.
And I was initially worried about generic functions in src/backend, to keep code duplication down, however they're in fact replacing manually duplicated code, so that doesn't seem to be a problem.
I agree that it'd be good to continue to evolve this as you discussed. #1171 adds a RawSocketAddr
type which is very close to what you describe for return values, and sounds like a good general direction.
I have have a few relatively minor comments, plus this needs a rebase. If you'd like help with the rebase please let me know.
src/net/socket_address.rs
Outdated
|
||
/// A trait abstracting over the types that can be passed as a `sockaddr`. | ||
/// | ||
/// Safety: implementers of this trait must ensure that `with_sockaddr` calls |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
As a minor style nit, this should be a # Safety
section header.
src/net/socket_address.rs
Outdated
#[repr(C)] | ||
pub struct SockAddrRaw { | ||
_data: [u8; 0], | ||
} |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
What would you think of renaming SockAddrRaw
to SocketAddrOpaque
?
There are two changes there:
Sock
->Socket
, because if we have some things prefixedSocket
and some prefixedSock
I expect I'll frequently forget which things use which prefixes.Raw ->
Opaque`, which I think better captures that this struct type doesn't describe the data layout.
src/net/mod.rs
Outdated
@@ -10,6 +10,7 @@ | |||
mod send_recv; | |||
mod socket; | |||
mod socket_addr_any; | |||
mod socket_address; |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Could we make this a pub mod
, and perhaps name it addr
, to keep SockAddr
and SockAddrRaw
from cluttering the rest of the net
API? It seems like most users won't ever need to use those directly.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Is it confusing that rustix::net::addr
then only contains those two, and not any of the other address types (SocketAddrUnix
, SocketAddrV4
, SocketAddrV6
, SocketAddr
, SocketAddrAny
, SocketAddrStorage
) that are one level up? Seems like at least SocketAddrStorage
and SocketAddrOpaque
should be next to each other since they represent similar C types.
Maybe move them all into rustix::net::addr
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Good idea to keep SocketAddrStorage
next to SocketAddrOpaque
.
It seems nice to keep SocketAddrV4
, SocketAddrV6
, SocketAddrUnix
, in rustix::net
where all the rest of the API that uses them are though, because that's the "regular" API.
What if we put SocketAddrOpaque
, SocketAddrArg
, and SocketAddrStorage
into a pub mod
named rustix::net::abstract
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Sounds good. abstract
might be confused with the abstract namespace for unix sockets, but I don't have a better name to propose.
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Also, abstract
is a Rust reserved keyword.
src/net/socket_address.rs
Outdated
/// `f` with a pointer that is readable for the passed length, and points | ||
/// to data that is a valid socket address for the system calls that accept | ||
/// `sockaddr` as a const pointer. | ||
pub unsafe trait SockAddr { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
And, what would you think of renaming this to SocketAddrArg
? Sock
-> Socket
for the same reason as above, and Arg
since it is for describing arguments; return values will need to use some other mechanism as you noted in the top comment.
f5ecd5e
to
7214eea
Compare
Rebased and made the requested changes. I named the new module I'll take a look at updating Since it looks like you're merging breaking changes to main for 1.0, should I go ahead and remove the address type specific functions?
|
I haven't thought of a better name yet, but I'll keep thinking 😄 .
👍
Yes, that'd be great! |
fbf85a8
to
c237ec1
Compare
Removed the address-type-specific variants of |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Cool, overall this looks great!
src/net/socket_addr_any.rs
Outdated
/// | ||
/// `storage` must point to valid memory for decoding a socket | ||
/// address. `len` bytes must be initialized. | ||
pub unsafe fn read(src: *const SocketAddrOpaque, len: usize) -> Self { |
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
This is pre-existing, but: it appears every user of this has a socklen_t
rather than a usize
, what would you think about making this argument take a socklen_t
, to save all users from having to .try_into().unwrap()
?
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
Changed the internal callers to construct it through a new SocketAddrBuf
that handles this. Not sure if the new public constructor pub unsafe fn new(storage: MaybeUninit<SocketAddrStorage>, len: usize) -> Self
should take usize
or socklen_t
-- I lean towards usize
as the convention in Rust, and to avoid needing to re-export socklen_t
(SocketAddrLen
?)
There was a problem hiding this comment.
Choose a reason for hiding this comment
The reason will be displayed to describe this comment to others. Learn more.
The thing that has me leaning toward socklen_t
is seeing places like this that silently cast the usize
back to socklen_t
. Perhaps we could make those .try_into().unwrap()
to eliminate the (admittedly remote, but perhaps not impossible) chance of silently truncating an address, but it seems cleaner to keep socket lengths in the type that the OS them to us in.
And yeah, I think it would be SocketAddrLen
. If you like, I can make that change.
c237ec1
to
3c58420
Compare
To support extensibility over address types, use sockaddr_storage and Into / TryInto conversions.
Removes: * `bind_any`, `bind_unix`, `bind_v4`, `bind_v6`, `bind_xdp` in favor of `bind`, * `connect_any`, `connect_unix`, `connect_v4`, `connect_v6` in favor of `connect` (leaving address-less `connect_unspec`) * `sendmsg_v4`, `sendmsg_v6`, `sendmsg_unix`, `sendmsg_xdp`, `sendmsg_any` in favor of `sendmsg_addr` (leaving address-less `sendmsg`) * `sendto_any`, `sendto_v4`, `sendto_v6`, `sendto_unix`, `sendto_xdp` in favor of `sendto`
3c58420
to
53b4738
Compare
Thanks! The socklen_t question is my only outstanding question now. |
#918
This adds a trait
SockAddr
, and implements it forSocketAddrV4
,SocketAddrV6
,SocketAddrUnix
,SocketAddrXdp
,SocketAddr
,SocketAddrAny
, and the newly-addedSocketAddrNetlink
. The syscalls that take asockaddr
are reimplemented in terms of this trait, removing hundreds of lines of duplicated code. It also simplifies the public interface, allowingrustix::net::{bind, connect, sendto, sendmsg_addr}
to take an(addr: &impl SockAddr)
, rather than needing separate functionsbind_v4
,bind_v6
,bind_unix
,bind_xdp
,bind_any
etc.The
SocketAddrAny
enum is replaced by a struct wrappingSocketAddrStorage
. This allowsSocketAddrAny
be fully generic and allows syscalls returning addresses to be used with any address type not known to rustix. Address types use.into()
/.try_into()
to convert to / fromSocketAddrAny
.