[sane-devel] Passing all scanner usage through local saned

Till Kamppeter till.kamppeter at gmail.com
Fri May 10 20:11:01 BST 2024


Hi,

this sounds interesting. I am running into a similar problem.

Generally we have immutable distributions. The core system and the applications 
are in their own, isolated sandboxes, which could be Snaps, Docker containers, 
Flatpaks, ... With this, each application brings its own libraries and they 
often are of mismatching versions, and also any system-provided, centrally 
stored scanner drivers (SANE backends) cannot be dlopened as the core system's 
or a driver container's file system is not visible inside the application's sandbox.

IP connections can usually be easily defined between sandboxes/containers though.

So my idea, mainly with the all-Snap Ubuntu Core Desktop in mind, but applying 
to any immutable distro, is to use the same IP protocol as driverless network 
scanners and printer/scanner multi-function devices already use. These protocols 
are well-defined, established in the industry, and (therefore) stable across 
different software versions and implementations.

In my design (derived from driverless IPP printing) the applications come with 
only the sane-airscan (written by Alexander Pevzner, CCed) backend, the backend 
which supports driverless scanning, currently eSCL and WSD, later perhaps also 
IPP Scan. All modern driverless printer/scanner multi-function devices 
understand either eSCL or WSD (and IPP for printing). There are also some 
driverless standalone scanners around which support these standard protocols. 
This way the applications talk directly to the scanners, without need of any 
centralized scanner support in the operating system.

Also USB devices can be driverless. Here the IPP-over-USB standard comes to play 
which maps the USB device onto localhost, port 60000 and following (should be 
actually HTTP-over-USB, as it supports all HTTP protocols: IPP, eSCL, WSD, web 
admin interface).

Using industry-standard protocols also allows connections across operating 
systems and does not limit to only SANE (we did it more than a decade ago with 
CUPS, replacing CUPS' own broadcasting/browsing protocol by DNS-SD).

For scanners which need a driver, as they have a non-standard communication 
protocol, we introduce emulations of eSCL scanners, the so-called Scanner 
Applications. At the front they appear as eSCL (driverless) scanners and at the 
back they are talking with the actual scanner device, converting the protocols 
internally. Like a physical network device they advertise the presence of the 
scanner via DNS-SD (Avahi under Linux) and the eSCL protocol allows clients to 
poll the full set of capabilities (resolutions, scan sizes, ADF, ...) from the 
Scanner Application and also to conduct the actual scan.

One Scanner Application can contain any amount of scanner drivers and there can 
be any amount of Scanner Applications installed on the system. So we can have 
one Scanner Application retro-fitting the whole sane-backends package and other 
Scanner Applications issued by scanner manufacturers to support their devices. 
Internally Scanner Applications do not need to use SANE, they can accomplish 
their job with whatever the developer considers best. So we will have native 
Scanner Applications not using SANE internally and retro-fitting Scanner 
Applications using SANE.

Applications which scan and scanner drivers (Scanner Applications) can be in 
different sandboxes and so be installed independently on immutable (and also 
classic) operating system distributions, so especially one can add scanner 
drivers to an immutable distribution this way, and as each sandboxed package 
brings their own libraries, they can work with different libraries. So 
especially also the situation of packages using different libraries in Nix OS 
gets solved this way.

For the implementation, on the client side there is not much to do. One only 
needs to have a SANE-supporting application and ship it together with the 
sane-airscan backend.

On the server/driver/device side is more to do but we are well into it. As we 
come from the situation of printer/scanner multi-function devices, out emulation 
is actually also an emulation of such a multi-function device if we want to 
support a non-driverless multi-function device.

Several years back we (at OpenPrinting) have already started with printing. All 
modern printers are driverless. they do driverless IPP printing. AirPrint, 
Mopria, IPP Everywhere, and Wi-Fi Direct Print are all just flavors of 
driverless IPP printing. Here the printer always advertises itself by DNS-SD. 
Then clients can find the printer and poll the printer's capabilities from the 
printer via an IPP request and then print the job in a standard data format 
(PDF, but also some raster formats for cheaper printers), so there is no need 
for a driver (aka device-model-specific software or data, like CUPS filters 
and/or PPD files) for printing.

For non-driverless legacy or specialty printers we have introduced Printer 
Applications, emulations of driverless IPP printers. To create such Printer 
Applications there is a standard library, PAPPL (Printer APPlication Library) 
written by Michael Sweet, author of CUPS. It contains everything which every 
Printer Application needs: Daemon, handlers for DNS-SD and IPP, web admin 
interface, ... and Michael also ha written two native (no CUPS filters and PPD 
files hidden inside) Printer Applications, hp-printer-app (for legacy PCL 
lasers) and LPrint (for label printers).

I have written pappl-retrofit, an additional library for PAPPL with which one 
can easily wrap classic CUPS printer drivers and PostScript PPD files into 
Printer Applications (retro-fitting).

Currently Akarshan Kapoor (CCed), GSoC contributor for OpenPrinting last year 
and this year, is adding scanner support to PAPPL, so that with PAPPL one can 
make both Printer and Scanner Applications, even support multi-function printers 
with one single application. He is adding eSCL support to PAPPL (which before 
only supported IPP printing) and SANE support to pappl-retrofit.

This way we get a universal Printer/Scanner driver format which allows for 
distribution-independent binary package and for adding drivers not only to 
classically installed but also to immutable operating systems.

We are snapping these Printer and Scanner Applications and putting them into the 
Snap Store. Currently you find all free software printer drivers which usually 
come with Linux distributions in 4 retro-fitting Printer Applications and the 2 
native Printer Applications from Michael Sweet. Scanner Applications will 
hopefully come soon.

Printer Applications and Scanner Applications are not required to get 
distributed as Snaps, one can also just install them classically or put them 
into other containers.

At OpenPrinting we have this year also a GSoC project on OCI (Docker, ROCKs, 
podman, ...) containerization to cover most immutable distros which are around.

For the issues you mentioned, network scanners are available, those on modern 
network multi-function devices usually directly, without need of a Scanner 
Application. SANE-shared scanners we can support by the planned 
sane-backends-retro-fitting Scanner Applications.

Scanner Applications can be configured to share scanners in the local network or 
to restrict them for only local use.

The eSCL being an industry standard protocol it will be supported by any version 
of sane-airscan and PAPPL once it has scanning support. No changes between 
software versions are expected.

Links:

Printer Applications: 
https://openprinting.github.io/achievements/#all-free-drivers-in-a-ppd-less-world---or---all-free-drivers-in-snaps
Scanner Applications: https://openprinting.github.io/current/#scanner-applications
PAPPL: https://github.com/michaelrsweet/pappl/
pappl-retrofit: https://github.com/OpenPrinting/pappl-retrofit/
LPrint: https://github.com/michaelrsweet/lprint/
OpenPrinting in the Snap Store: https://snapcraft.io/publisher/openprinting
LPrint in the Snap Store: https://snapcraft.io/lprint
Scanning support for PAPPL: 
https://dev.to/kappuccino111/sandboxing-scanners-a-leap-into-the-driverless-realm-gsoc-23-report-3eci 
  https://www.youtube.com/watch?v=AAeUseU35Cc

    Till


On 09/05/2024 17:39, Guillaume Girol via sane-devel wrote:
> Hello,
> 
> I'm a downstream maintainer of SANE on NixOS, a linux distribution. I
> consider modifying NixOS to make it so all application using libsane
> would actually only use saned, and never load the backends to directly
> access scanners themselves. I send this message to the mailing list to
> know if I missed reasons it could be a bad idea.
> 
> Rationale
> =========
> 
> NixOS is quite different from typical linux distributions in that there
> is no globally installed library. /usr/lib does not exist and without
> special packaging care, dlopen() never finds anything. Each library is
> installed in a unique prefix /nix/store/unique-id/lib/foo.so so several
> versions of the same library can coexist. Exeecutable find the
> libraries they depend on via explicit RPATH. As a result I can have an
> old version of python in /nix/store/some-id/bin/python using an old
> version of glibc in /nix/store/other-id/lib/libc.so via RPATH and the
> rest of the system using a newer version of glibc in /nix/store/yet-
> another-id/lib/libc.so also via RPATH.
> 
> This does not work for SANE as it uses dlopen() to find backends
> depending on a single, global configuration file. For now we have an
> exception to the "no lib installed globally" design for SANE. However
> this is not perfect: if I use an old version of, say, simple-scan, it
> may dlopen() more recent version of some SANE backend, which depends on
> a more recent glibc than the version that old simple-scan brings with
> its RPATH. Thus dlopen() fails. In practice this means that software
> installed from the past or the future often fails to scan, whereas this
> usually works quite well for other functionnality.
> 
> Solution considered
> ===================
> 
> To solve this, I want applications using SANE to stop using dlopen() to
> access the scanner, but to use a network protocol instead. This is a
> bit like glibc can talk to nscd over a socket instead of dlopening nss
> modules.
> 
> The solution I'm considering consists in linking all normal
> applications to a stripped-down variant of libsane which only has the
> network backend and is configured to connect to a saned instance on
> localhost (instead of obeying what you would find in /etc/sane.d on
> typical distros). Each application comes with its own copy of this
> libsane, it's not global anymore. (Don't mind the disk space cost, all
> of NixOS works this way, this is part of the tradeoff). When the user
> configures their system for scanner support, a global instance of saned
> is setup which is linked against a full-fledged copy of libsane obeying
> the full configuration files you would typically find in /etc/sane.d.
> 
> When an old application attempts to scan, it uses its own, old version
> of libsane to talk to a recent saned which dlopen()s sane backends of
> matching version, so all works fine.
> 
> Possible issues?
> ================
> 
> Any issues with this design I missed? In my light testing, it appears
> to work quite fine. The problems I found:
> - all users can use the scanners instead of just users in the lp or
> scanner group previously. I suppose this can be solved with a firewall
> (firewalls can filter the uid of local sockets).
> - network scanners are not available. I propose a fix in
> https://gitlab.com/sane-project/backends/-/merge_requests/834
> - is the network protocol that saned uses stable across versions? In my
> testing, it is, but maybe it's by sheer luck.
> - maybe stuff I have not considered.
> 
> 
> Cheers,
> Guillaume Girol
> 
> 




More information about the sane-devel mailing list