-
Notifications
You must be signed in to change notification settings - Fork 231
Add trait to reduce duplicated code between socket address types, implement netlink addresses #1004
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
Conversation
f694272 to
4c1c746
Compare
|
As a quick update here, I am looking forward to reviewing this; I've just been busy. |
niklaswimmer
left a comment
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. |
sunfishcode
left a comment
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 prefixedSocketand some prefixedSockI 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
| 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 |
sunfishcode
left a comment
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.
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. The same rationale might apply to the usize closure argument in SocketAddrArg::with_sockaddr.
If you like, I can make that change.
Yes, please do.
3c58420 to
53b4738
Compare
|
Thanks! The socklen_t question is my only outstanding question now. |
|
Should I rebase #1171 onto this? Specifically, I would use |
|
@colinmarc Yes, please do rebase it on top of this. I've now added the |
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`
49e8170 to
f8a00a6
Compare
|
Interesting. It appears this PR breaks code like I've now changed the tests to avoid doing this. It's a little unfortunate that this common idiom doesn't work, but my guess is it's ok. |
|
Thanks! |
#918
This adds a trait
SockAddr, and implements it forSocketAddrV4,SocketAddrV6,SocketAddrUnix,SocketAddrXdp,SocketAddr,SocketAddrAny, and the newly-addedSocketAddrNetlink. The syscalls that take asockaddrare 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_anyetc.The
SocketAddrAnyenum is replaced by a struct wrappingSocketAddrStorage. This allowsSocketAddrAnybe 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.