-
Notifications
You must be signed in to change notification settings - Fork 20
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
ipp-usb and USB backend: do not claim IPP-over-USB endpoints until needed #28
Comments
Actually, it would be better if ippusbxd did not claim the IPP-USB interfaces until a connection comes in. Transferring this to the cups-filters project. |
@michaelrsweet The IPP-over-USB daemon which is currently used by default is Moving the issue on to @alexpevzner, could you have a look and help @bitwombat here? Thanks. @michaelrsweet by the way, |
Simultaneous access to device using IPP over USB on one interface and legacy printer driver (Class 7 Proto 2) on another interface on some devices work unreliable; it causes IPP over USB session to fail (see #26, for example). Also, CUPS performs class-specific SOFT_RESET on interfaces it uses. I experimented with SOFT_RESET in the So I'd prefer to avoid dynamic allocation of the IPP over USB interfaces, I believe it will not work reliable in all cases. There are also devices, that claims IPP over USB support (Class 7 Proto 4), but it actually doesn't work (see alexpevzner/sane-airscan#68). So it's not enough for CUPS to skip all devices that support Class 7, Proto 4; CUPS should check that So the solution 1 from the Michael's list looks most reliable and promising. libusb returns Alternatively, we can add some IPC channel (in a form of AF_UNIX socket), where |
@alexpevzner If ipp-usb has claimed a USB device then the USB backend can never do so. We explicitly don't try to claim a device when enumerating available printers because a) the printer might be in use, and b) doing so can have some unfortunate side-effects (slows down enumeration, wakes up printer, potential kernel driver issues, etc.) The reason this bug ended up here is that there are multiple Printer Applications (i.e. not just CUPS) that will soon be competing to talk to USB-connected printers, and if ipp-usb always claims the IPP-USB interfaces then they will never be able to print over legacy USB (I'm primarily thinking of Gutenprint users). Their solution will be to remove ipp-usb entirely vs. just using the protocol they want to talk to the printer, which probably isn't what we want... :) I'm not asking for dynamic allocation. I'm saying that until you get a socket connection there is no need to claim any of the IPP-USB interfaces. Once ipp-usb is in use, claim them all and hold them until you haven't had any traffic for some amount of time (2 minutes), then shut everything down. |
I need to claim USB interfaces at least to query for device characteristics, which I announce via DNS-SD. If one half of device (say, printing) is served by legacy driver, while another half (say, scanning) is served driverlessly, it may lead to ugly interference, when user switches from scanning to printing or visa versa. I understand the need of switching between IPP over USB and legacy access for some users (mostly in cases when device offers more functionality via proprietary USB driver rather that in driverless manner), but can't figure out the reliable approach to implement it. |
@alexpevzner Well, can you claim the interface long enough to do the query, then release it until somebody else wants to talk over IPP-USB? |
If somebody will steal a device when it is already advertised, we will get a lot of complains about "device found but doesn't work" both at printing and scanning side. Can we make selection between legacy/driverless access modes more explicit for users rather that "first attempt wins"? |
@alexpevzner I don't see how. Right now a legacy USB printer is only claimed when there is an active print job. However, an IPP-USB printer is claimed as soon as the printer is connected and never released. Either we need to have ipp-usb only claim the IPP-USB interfaces when they are needed, or we need to have the USB backend hide all printers that support IPP-USB (and make sure things like PAPPL do the same) so that we don't get a lot of frustrated users asking why they can't print using driver/Printer Application XYZ. |
#26 demonstrates the possible scenario on a real hardware.
After using one of these interfaces for printing with proprietary USB driver, sane-airscan connected via ipp-usb to another interface stops working (it was working before printing). This is definitely a firmware bug, but who knows how many devices are affected? |
Why not do the following: On startup ipp-usb claims the printer to poll its properties needed for advertising the emulated IPP network printer, then it releases the printer to allow access for everyone. Then if a job comes in later the access software (ipp-usb or CUPS backend) through which the job is sent claims the printer, passes on the job, and releases the printer afterwards. As a printer can only print one job at the same time anyway this should be no problem. Imporetant is also that if a job is printing and therefore the printer claimed/busy and another job is coming up through the other access method, this second job has to wait somehow until the first finishes and the printer gets released. |
From the Is it possible to implement an explicit arbitration? Say, All open source drivers are in our hands, so it should not be impossible to implement this approach. |
@alexpevzner There is no perfect way to know when an IPP print job is done (short of eavedropping on the IPP messages), but an inactivity timeout should be sufficient for this scenario. Doing an explicit arbitration mechanism introduces a dependency on yet another piece of software and is not something I'd want to do just to support what is essentially an edge case - and IPP-USB printer should immediately get auto-added using the IPP Everywhere "driver" since IPP-USB support implies AirPrint (which requires it and eSCL support if there is a scanner) so there is no hard requirement for us to support a specialized printer driver/application. So that brings us back to what to do about IPP-USB printers and the USB backend:
(I should note that macOS claims IPP-USB interfaces and doesn't give them up, so there is precedent to just running IPP-USB printers in IPP-USB mode all the time...) |
OK, let's do as Apple does :-) Anyway, when skipping IPP-USB devices, it's better to check that |
@alexpevzner That's the trick - there is no reliable way to determine whether ipp-usb is installed/active on the system. |
We can add it. Say, in a form of AF_UNIX socket, speaking a simple protocol. |
@alexpevzner But what would be the server? And what would the interface look like? |
@alexpevzner Also, don't forget that this needs to work with a snapped CUPS... :/ |
Interface would be as we will agree. Probably, something simple, text-based, potentially extendible. Some text-based protocol, like FTP or SMTP. |
We can also speak through Avahi, if we will add USB "coordinates" to the TXT part of DNS-SD announces. But I'm not sure it will be convenient at the CUPS side. |
The snapped CUPS can read the DNS-SD records of the printers which ipp-usb advertises, as it uses a Snap interface which allows it to use Avahi, already for simply discovering printers (and also for sharing printers). If you add a TXT record entry telling that this device is IPP-over-USB and which USB coordinates it has and which channels are occupied (in a simple text string), then the USB backend in the snapped CUPS could use this info to know that a printer device is there but occupied by ipp-usb. |
@tillkamppeter If we were to use Avahi, it would probably be better to advertise a separate service instance using the bus and port numbers, e.g. BBPP._ipp-usb._tcp (where "BB" and "PP" are the bus and port numbers in hex) with a port number of 0. |
@michaelrsweet as in case of a successful connection of ipp-usb to printer we have to advertise the printer as IPP printer anyway, why would we need the separate service entry for the IPP-over-USB connection? Why can't we add a TXT record entry like |
@tillkamppeter Because the USB backend has to look up the device! If we look for all _ipp._tcp services, we will have a lot more than just the local IPP-USB printers. And then we need to look at the TXT records to find the key(s) with the bus and port numbers. But if we have a secondary service entry specifically for IPP-USB that doesn't depend on parsing the TXT record, then the USB backend can just query for the device it is interested in (or browse up front so it has a list of USB devices to blacklist). The Avahi API makes adding another service entry super-easy, so it is one line of code to add it to ipp-usb (same as a TXT key in complexity) but vastly more efficient code in the USB backend to do the lookup. |
@tillkamppeter, I strongly discourage against simultaneous access to the same device via the I agree with @michaelrsweet, if there is no other considerations, let's go this way. Should I add any additional information to the TXT records of these |
@michaelrsweet, great, this eliminates the time-consuming resolving with Avahi, one of the things which also makes tools like |
@alexpevzner do not use the TXT record, stuff everything into the service name, to avoid time-consuming resolve calls on Avahi. |
OK. One small thing. When new device is plugged into the system, the legacy driver may receive PnP notification from libusb and attempt to make skip/handle decision before I believe, a small delay (say, 1 second) would be enough to resolve this race. |
@alexpevzner Just adding the service with the necessary addressing information (bus+address? or do we also need the ports list?) and no TXT record is sufficient. Use a port number of 0 (which basically says "I'm defending this name"). @tillkamppeter You do not need to resolve a service to get its TXT record. You can query the TXT record directly, and this is what we do in the dnssd backend, in the libcups cupsEnumDests function, and in PAPPL's DNS-SD printer discovery function - all so that you don't wake up printers. You only need to resolve to get the address(s) and port of a service. |
For each device that ipp-usb handles, a service with the name in the form _BBPP-ipp-usb._tcp, where BB and PP are USB bus/port numbers in hex, is advertised The purpose of this change is to let legacy drivers to easily detect that device is handled by the ipp-usb, to avoid possible conflicts See discussion at #28
Done. @michaelrsweet, RFC requires that service name consist of exactly 2 DNS labels, and Avahi enforces it, so I use |
@alexpevzner No, the service type is _ipp-usb._tcp and the service instance name is the bus and address, e.g.:
|
For every USB port, handled by ipp-usb, service with the following parameters is advertised: Instance: "BBPP", where BB and PP are bus and port numbers in hex Type: "_ipp-usb._tcp" Regardless of the ipp-usb configuration, these services are advertised only to loopback interface
OK, updated. I've just though that it may make sense to advertise the real TCP port number instead of 0, to help matching of USB devices with corresponding TCP port. Currently nobody needs it, but it may be useful in the future. What do you think? |
@alexpevzner Sure, since we have a port number, let's use it. |
Done too |
Now in release |
@bitwombat reported issues printing to a Brother printer via USB: Apple Issue #5908
Basically, this is an AirPrint printer that supports IPP-USB. When connected, ippusbxd claims the endpoints used for IPP-USB, which happen to also be the endpoints needed for legacy USB printing. Therefore, the USB backend can see it but not access (claim) it.
We should hide such printers so that the IPP-USB listing gets used. And in particular that means the IPP Everywhere driver can be used instead of a vendor driver.
Possible solutions:
Option 1 is probably the best solution, then 3.
The text was updated successfully, but these errors were encountered: