104 lines
5.2 KiB
Markdown
104 lines
5.2 KiB
Markdown
# 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.
|