-
Notifications
You must be signed in to change notification settings - Fork 34
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
Hotplug events on device connect and disconnect #5
Comments
I looked into working on this as it is one of the things we'd want to have in order to switch from rusb. Avoiding a For the direct kernel route, there is a kobject_uevent crate to help with unpacking the netlink messages. However, I suspect there may be timing issues. If you listen to the netlink socket, you get the notifications of new devices at the same time the |
Well, there's the ugly option of spawning a |
Also came across https://github.com/cr8t/udev -- @cr8t started a pure-rust implementation of libudev just a few days ago, if we want to rely on the stability of udevd's socket messages. |
As I understand it, the upstream position is that the udevd messages are subject to change, and that the only interface they promise to keep stable is the libudev API/ABI. So a rust reimplementation of libudev would be subject to the same risk as statically linking libudev: it may randomly break on a new systemd release. |
Still very early days, but my intentions are to upstream changes to
I've made an effort to follow Currently, working on the public API helper functions. If there is something that |
Is it intended to work on distributions that use systemd-udevd, or only on distros with eudev? |
I don't know yet. Ideally, it will support as many platforms as possible. That may end up using something like a |
@kevinmehall udevrs |
It seems that the current Perhaps the socket interface between udev daemon implementations and libudev or similar clients could be considered de facto stable at this point. But it's dangerous to assume that; anything monitoring these messages should check the magic value and handle a mismatch - at least safely, ideally gracefully. @cr8t it doesn't look like your code currently checks the magic field - do you have any plan in mind for how to handle that? |
I was not aware this magic value had changed at any point in the past, and missed handling a mismatch. There is now a fix merged, and will be included in the next patch release. There may still need to be some testing around the difference between If there are users that have systems with different magic bytes, they are welcome to open an issue, and we can address it. Until then, I'm not that concerned about it. |
That would be excellent! It seems like if there's a magic number to detect protocol versions and the protocol hasn't changed in years (and across a fork), they're at least thinking about protocol compatibility even if they don't want to guarantee it. So while not using |
For what it's worth, I've tried to stay as close as possible with
What code area should the |
nusb intentionally doesn't have a context object like libusb and rusb. Its function for listing devices is just a free function at the top level of the crate, and I imagine this being something similar. Would an API like this make sense? fn watch_devices() -> HotplugWatch;
struct HotplugWatch(platform::HotplugWatch); // Linux version owns UdevMonitor.
impl Iterator for HotplugWatch {
type Item = HotplugEvent;
}
impl Stream for HotplugWatch {
type Item = HotplugEvent;
}
/// Platform-specific opaque device identifier that can be used to see if two devices are the same,
/// or remove a disconnected device from a user-maintained set of `DeviceInfo`s. We'd add a new
/// `id` method to `DeviceInfo` to get its `DeviceId`. I assume we can't get all the `DeviceInfo` fields
/// for a disconnected device on all platforms, so a disconnect event is only the ID.
/// On Linux, this would probably be the `busnum` and `devnum`
#[derive(Clone, Eq, PartialEq, Hash)]
struct DeviceId(...);
enum HotplugEvent {
Connected(DeviceInfo),
Disconnected(DeviceId),
Error(crate::Error),
} Like the implementation of You could skip the async Libusb hotplug allows filtering by a few fields like vendor ID and product ID. If there were APIs for that I assume UdevMonitor could apply those filters at the udev level. But I'm not sure it's necessary, because there aren't going to be enough USB events for performance to be an issue, and using |
Started implementing hotplug for Windows and macOS on #20. |
I've decided against using Instead, I've gone ahead and added netlink socket support in rustix (which became its own yak shave), and wrote my own code to receive and parse the netlink messages from udev. It doesn't do the fancy in-kernel event filtering with BPF that libudev does, but it's the simplest thing that works, and there's no unsafe code outside of rustix. |
I can dedicate some time to fixing that. It's the part of the code base I'm least confident about.
Fair about the LGPL licensing. Regarding non-idiomatic Rust, I wanted to start with as close to a literal translation as possible, and then iterate on making the implementation idiomatic Rust. This is typically how C to Rust ports proceed.
That's awesome!
I'll review your code, and see if I can do something similar in userland without BPF. Honestly, I would also prefer to avoid BPF if possible. Again, this is a holdover from the translation from |
Changes the license to LGPL-v2 or later after a re-reading of the `eudev` license. After discussion in kevinmehall/nusb#5 (comment), and reviewing the terms of LGPL, it seems required to also license `udevrs` under LGPL. `udevrs` is a very close translation of `eudev`. Regardless of how much the project changes to be more idiomatic Rust, it will always have its roots as a port of `eudev`. IANAL, so to keep things simple let's just use the same license.
README: add a project README.md
udev
NETLINK_KOBJECT_UEVENT
socketThe text was updated successfully, but these errors were encountered: