Files
juergen 843c6866a5
ci/woodpecker/push/build Pipeline was successful
fix airprint discovery
2026-10-19 22:44:08 +02:00

5.2 KiB

Design

Context

See proposal.md — Why.

The relevant facts, all from the running system (macOS 27.0.1 build 26A434, CUPS 2.4.2 in the container) and the CUPS sources:

  • The container registers the queue with CUPS' own DNS-SD code (scheduler/dirsvc.c): _printer._tcp unconditionally, and _ipp._tcp / _ipps._tcp with the sub-type list from DNSSDSubTypes. The list is passed to one DNSServiceRegister call as <type>,<subtypes> (snprintf(temp, "%s,%s", type, subtypes)), so DNSSDSubTypes decides the whole sub-type set.
  • DNSSDSubTypes defaults to _cups,_print,_universal (scheduler/conf.c) and is settable with the BrowseDNSSDSubTypes directive.
  • The queue's TXT record already carries what a driverless client needs: URF, pdl=…,image/urf, TLS=1.2, Color=T, Duplex=T, mopria-certified=1.3.
  • macOS' Add Printer browser (AddPrinter.app's PMBrowser.framework) browses _ipp._tcp,_cups and _ipp._tcp,_universal (plus the _ipps forms) and keys a printer's registration types by the regType the browse callback reports. -[DNSSDPrinter isShared] is YES when any of them ends in ,_cups, and -[DNSSDPrinter airprintMatch] returns nothing when isShared is YES.

Goals / Non-Goals

Goals:

  • The queue is advertised so that macOS classifies it as an AirPrint printer and offers the driverless driver, without changing anything else a client sees.

Non-Goals:

  • Replacing CUPS' DNS-SD advertising with hand-written Avahi service files, or changing the TXT record CUPS generates. CUPS' advertisement works for every other client; only the sub-type set is wrong.
  • Changing the certificate, the queue's PPD or the device URI.

Decisions

Drop _cups from DNSSDSubTypes instead of suppressing CUPS' registration.

BrowseDNSSDSubTypes _print,_universal removes exactly the marker that makes macOS treat the queue as shared, while keeping the _universal sub-type that makes isAirPrint YES. _print is kept because CUPS ships it by default and dropping it would remove information some clients use, with no benefit here.

Alternatives considered:

  • Advertise the queue with a hand-written Avahi service definition and turn CUPS' own advertising off. Gives full control over sub-types and TXT, but duplicates what CUPS already generates (including the UUID and printer-type TXT that CUPS clients resolve the queue with) and has to be kept in sync with the queues. Only worth it if the sub-type turns out not to be sufficient.
  • Keep _cups and patch macOS' classification — not possible; it is the client's behaviour.
  • Stop sharing the printer (printer-is-shared=false) — would remove the queue from mDNS entirely.

Keep CUPS' TXT record and the /cups device URI.

The /cups path marker and the printer-type TXT key come from CUPS' own advertisement and tell CUPS clients that this is a CUPS server; they are what makes dnssd://…/cups?uuid=… resolve. macOS' sub-type-based isShared is a separate mechanism from that marker, so removing the sub-type keeps CUPS clients working while fixing macOS' driver choice.

Rely on airprintMatch's remaining requirements being satisfied by the existing advertisement.

After the sub-type fix, airprintMatch also needs a device-ID entry with the TXT-derived URF: key and a dnssd servicetype: entry for _ipp._tcp / _ipps._tcp, and a locally built generic URF PPD. Those come from the printer's TXT record, which already carries URF and pdl (PMBrowser normalises TXT keys to its KEY: form) and from the service type in the browse result — the same inputs a real AirPrint printer provides. If the GUI still offers only the generic driver, the fallback is the Avahi service file mentioned above.

Risks / Trade-offs

  • [The queue is still classified as shared because the /cups device URI or printer-type TXT matter in a code path not covered by the disassembly] → Small risk; the disassembly of isShared/isAirPrint/airprintMatch covers the driver-choice gate. Verify on the client; fall back to an Avahi service file if needed.
  • [Some client relies on the _cups sub-type to identify the server] → CUPS' dnssd backend uses the TXT printer-type/cups_shared marker for that, not the sub-type, so the /cups URI is unchanged. Verify with lpinfo -v on a CUPS client.
  • [cupsctl's rewrite of /etc/cups/cupsd.conf drops the directive] → cupsAdminSetServerSettings() copies unrecognised directives through verbatim (cups/adminutil.c), so BrowseDNSSDSubTypes survives the cupsctl --share-printers --remote-admin the entrypoint runs after cupsd has started. Confirmed by reading the write loop, not by a live run.
  • [macOS caches the previous classification for an existing printer entry] → Nothing the server can do; the printer has to be removed and added again. It is documented in the README.

Migration Plan

Rebuild and redeploy the image; no volume reset. cupsd re-registers the queue's services on start and drops the _cups sub-type, so the change takes effect immediately (mDNS caching on clients aside). Rollback is redeploying the previous image; the extra sub-type reappears and macOS falls back to the generic driver as before.