(18. Juni 2007 — tk)

Druckserver für HP JetDirect, remote LPR und Helios

Anbei die Abfallprodukte eines relativ »komischen« Auftrags, der uns die letzten Tage in Atem hielt: Eine MacOS X Kiste soll nach außen hin so tun, als ob sie ein Windows-basiertes Fiery-RIP wäre. Muß also von außen per AppleTalk, per SMB/CIFS, »HP JetDirect« (TCP/IP Streams auf Port 9100) und »Remote LPR« (Port 515) erreichbar sein und idealerweise auch noch mit einer auf dem Mac laufenden Helios-Installation zu verheiraten sein.

Die Aufgabenstellung resultierte aus einem auf den ersten Blick unerklärlichen Problem in einer größeren Agentur, in der seit ein paar Tagen die beiden auf »Windows XP embedded« basierenden Fiery-RIPs für große Farbkopierer sich teils im Viertelstundentakt mit Bluescreen verabschiedeten. Um die Problematik an sich in Ruhe analysieren zu können, musste erstmal eine Situation geschaffen werden, in der wenigstens eines der RIPs irgendwie so vom Netzwerk isoliert werden konnte, so daß zwar Druckaufträge durchkamen aber nicht die »bösen« Netzwerkpakete, die offenbar für die Abstürze verantwortlich sind (und das Äquivalent einer Kernelpanik in »Efi Pkt Filter Driver« auslösen).

Die Lösung war dann quasi »galvanische Trennung«, d.h. zwischen Windows-RIP-Rechner einen Mac mit zwei (nicht routenden) Netzwerk-Schnittstellen und MacOS X 10.4, auf dem Helios UB und unsere Erweiterungen lief. Damit das Ganze nicht in eine Rekonfigurations-Orgie auf den 500 Macs/PCs im Netz ausarten musste, war die Idee, den Mac nach außen hin zusätzlich den AppleTalk-Namen des RIPs als auch die IP-Adresse übernehmen zu lassen, die Druckjobs mit allen möglichen Protkollen entgegenzunehmen, intern in Helios’ Spoolsystem zu stecken und auf dem anderen Netzwerk-Interface, an dem nur das Fiery-RIP hing, per TCP/IP-Streams auszugeben.

AppleTalk-Druckaufträge von den Macs wurden direkt seitens EtherShare entgegengenommen. Für die Windows-Clients, die alle per HP JetDirect/SockApp druckten, musste es aber noch ein kleiner LaunchDaemon sein, der von außen Druckdaten auf Port 9100 entgegennahm und direkt ins Spoolsystem des Macs stellte. Da das Helios’ lpr-Kommando leider keine Druckjobs an »stdin« annimmt sondern eine temporäre Datei haben will, entschieden wir uns dafür, in MacOS X’ Spoolsystem zu drucken und mittels eines eigenen CUPS-Backend den Druckjob dann an Helios weiterzureichen.

Anbei also der LaunchDaemon, der als /Library/LaunchDaemons/de.kaiser-edv.socket.plist abgespeichert und per launchctl load /Library/LaunchDaemons/de.kaiser-edv.socket.plist geladen werden sollte. Anschließend verhält sich der Mac wie ein beliebiger HP JetDirect-fähiger Drucker und akzeptiert Druckjobs auf Port 9100 und steckt diese in die CUPS-Queue mit der Bezeichnung »IPC1-Nr1-EG_Drucken« — die Zeile ist also in jedem Fall anzupassen, bevor der LaunchDaemon geladen wird!

<?xml version="1.0" encoding="UTF-8"?> 
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Disabled</key>
	<false/>
	<key>Label</key>
	<string>de.kaiser-edv.socket</string>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/bin/lp</string>
		<string>-d</string>
		<string>IPC1-Nr1-EG_Drucken</string>
		<string>-o</string>
		<string>raw</string>
		<string>-o</string>
		<string>job-sheets=none,none</string>
	</array>
	<key>Sockets</key>
	<dict>
		<key>Listeners</key>
		<dict>
			<key>SockServiceName</key>
			<string>pdl-datastream</string>
			<key>SockType</key>
			<string>stream</string>
		</dict>
	</dict>
	<key>inetdCompatibility</key>
	<dict>
		<key>Wait</key>
		<false/>
	</dict>
</dict>
</plist>

Noch eine Randbemerkung: Wenn man »Printer Sharing« unter aktuellen MacOS-Versionen aktiviert, wird seitens MacOS X auch der /usr/libexec/cups/daemon/cups-lpd bei Bedarf gestartet, um Druckjobs per »Remote LPR« anzunehmen. Dummerweise wird dabei seitens Apples eigenem LaunchDaemon dann dafür gesorgt, daß eine zusätzliche Banner-Page vor jedem Druckjob ausgedruckt wird und in jedem Fall auch der Druckjob erneut auf dem Mac geprüft und ggf. gefiltert wird. Wenn man beides verhindern will (also sicherstellen, daß der Druckjob ohne Manipulationen 1:1 durchgereicht wird), empfiehlt es sich, einen eigenen LaunchDaemon einzusetzen, der bspw. als /Library/LaunchDaemons/de.kaiser-edv.cups-lpd.plist gespeichert und analog zu obigem launchctl-Aufruf ins System geladen wird:

<?xml version="1.0" encoding="UTF-8"?>
<!DOCTYPE plist PUBLIC "-//Apple Computer//DTD PLIST 1.0//EN" "http://www.apple.com/DTDs/PropertyList-1.0.dtd">
<plist version="1.0">
<dict>
	<key>Disabled</key>
	<false/>
	<key>Label</key>
	<string>de.kaiser-edv.cups-lpd</string>
	<key>ProgramArguments</key>
	<array>
		<string>/usr/libexec/cups/daemon/cups-lpd</string>
		<string>-o</string>
		<string>job-sheets=none,none</string>
	</array>
	<key>Sockets</key>
	<dict>
		<key>Listeners</key>
		<dict>
			<key>SockServiceName</key>
			<string>printer</string>
			<key>SockType</key>
			<string>stream</string>
		</dict>
	</dict>
	<key>inetdCompatibility</key>
	<dict>
		<key>Wait</key>
		<false/>
	</dict>
</dict>
</plist>