Open niklaswimmer opened 11 months ago
Interesting question.
I think my preference here is to add a Bluetooth
arm to SocketAddrAny
for bluetooth, containing a SocketAddrBluetooth
, similar to the Unix
arm, which encapsulates a bluetooth address, and then teach the encode/decode logic to handle it.
That said, at a quick search, I found about 40 sockaddr_*
types in Linux's headers. I don't have any idea how commonly used they all are. If rustix is going to end up supporting a lot of them, it may make sense to switch over to just exposing arbitrary bytes and letting users or other crates sort it out.
However, my guess is, for now, it makes sense to stick with typed interfaces and adding address families such as SocketAddrBluetooth
when people have a need for them, and we'll see how far we get.
Does that make sense?
I tried to add SocketAddrNetlink
to rustix but it involves an incredible amount of code duplication. Currently there's a copy of connect
, bind
, sendmsg
, sendto
for every single type of sockaddr and I don't think that'll be sustainable if more types of addresses are to be added.
The purpose of having connect_v4
/connect_v6
/connect_unix
instead of just connect
/connect_any
is just to avoid the construction of a SocketAddr
/SocketAddrAny
in common cases. Compared to V4/V6/Unix, I assume all other socket address types are far less commonly used, so it seems ok to just add entries to SocketAddrAny
and use connect_any
, and not add new specialized connect_*
etc. routines. Does that sound feasible?
For clarification, I am talking about the syscall side. connect_v4/connect_v6/connect_unix
all just encode the sockaddr and perform a syscall.
Would it make sense to have a SocketAddr
trait, that just does encode and decode to sockaddr_*
?
trait SocketAddr {
fn encode(&self) -> SocketAddrStorage;
fn decode(storage: &SocketAddrStorage) -> Result<Self>;
}
I am not sure why we currently have two methods of encoding/decoding, and duplicate for both backends for each sockaddr (4 redundant copies!).
Rustix can currently not be used to bind sockets which are not unix or ip. The only real requirement on a socket address is that it starts with an u16 (the address family) - judging from the types used in the definition of the bind syscall.
My specific use case is binding bluetooth sockets and my current workaround is to just call
libc::bind
instead (using the fd returned by rustix'ssocket_with
).I am unsure what a good API would look like, but ideally it would not require me to construct a
[u8]
array myself and instead work with structs which are then automatically converted into byte arrays when it comes to invoking the syscall. For my use case I wrote a helper module that uses unions to convert some struct into a libc::sockaddr if you want to take a look.This issue also blocks usage of eyra for any programs that need to work with some non-well-known sockets.
I would be happy to help implementing this API, but as noted above I am not sure about the design and would require some input.