[offtopic] Incomplete data received with scripted netcat that emulates a JetDirect printjob receiver
Kurt Pfeifle
kurt.pfeifle at infotec.com
Sat Jun 7 20:41:24 PDT 2008
Executive Summary:
==================
I'm trying to create a primitive port listener for CUPS which emulates AppSocket/JetDirect behaviour. It is meant to forward incoming jobs to a certain printer (say, "targetprinter at cupshost"). For that purpose I'm using a shell (Bash) script that utilizes netcat to listen on the receiving port (let's say, 9111).
All works perfectly well directly in the shell. But I have problems receiving the full job when I run this basic setup via a set of scripts.
(This is not a CUPS problem, I know. But I still hope some more knowledgable Bash scripter (on this list) than I am can pinpoint the exact cause of the problem and help me solve it.)
Details for interested readers:
===============================
First, how it works directly in the shell...
I start the listener like this in one console window on my host, that currently has (amongst others) the IP address 11.12.13.14:
-------- snip ----------------
while true; do
netcat -v -v -w 3600 -n -s 11.12.13.14 -l -p 9111 \
| lp -h cupshost -d targetprinter -
sleep 1;
done
-------- snap ----------------
To print to this listener, you may use any CUPS queue with a "socket://11.12.13.14:9111" backend (or the respective Windows variant of such a backend, called "port monitor").
However, when I try to transfer this concept into a set of scripts, something goes wrong, and I have no clue why.
My scripts are 3:
1. /etc/init.d/rclistener
2. /usr/local/bin/listener-watchdog
3. /usr/local/bin/listener-wrapper
ad 1: "rclistener" automatically starts the "listener-watchdog" (in the background) via the standard SysV concept.
ad 2: "listener-watchdog" holds a variant of the above loop: basically: "while true; listener-wrapper; done".
ad 3.: "listener-wrapper" runs the listening netcat and pipes the incoming data to the CUPS queue.
This works only for "small" printjobs. Larger jobs get truncated and therefore do not print.
You may reproduce the problem without wasting too much harddisk space (or without even running CUPS) by using this variant of a listener, that does not involve piping to a CUPS queue, but to a compressed file (to be started in one console window):
-------- snip ----------------
while true; do
now=$(date +%s)
netcat -v -v -w 3600 -n -s 11.12.13.14 -l -p 9111 \
| gzip - \
> /var/spool/netcat/${now}.prn \
&& gzip /var/spool/netcat/${now}.prn
sleep 1;
done
-------- snap ----------------
As "sender", we can use a different virtual IP address on the same host which we created with the command
ifconfig eth0:1 10.0.1.2
On the sender, instead of a CUPS client we'll use another (sending) netcat that uses highly compressible file created by /dev/null output:
-------- snip ----------------
while true; do
dd if=/dev/zero bs=512 count=1000000 \
| nc -n -vvv -s 10.0.1.2 11.12.13.14 9111;
sleep 1;
done
-------- snap ----------------
This setup reliably sends chunks of 510,200,000 Bytes to the listener side which stores it to double-compressed files of a size of 272 Bytes each (be careful when you expand them again -- they are "nullbyte bombs" that can easily eat your available disk space).
(On both sides, listener and receiver, use [ctrl]+[c] to stop the respective loops...)
On the sending side, you'll see a repetition of this output of netcat on stderr:
(UNKNOWN) [11.12.13.14] 22222 (?) open
1000000+0 records in
1000000+0 records out
512000000 bytes (512 MB) copied, 17.497 s, 29.3 MB/s
sent 512000000, rcvd 0
The receiving netcat will output this:
listening on [11.12.13.14] 22222 ...
connect to [11.12.13.14] from (UNKNOWN) [10.0.1.2] 25261
sent 0, rcvd 512000000
However, this basic setup stops working reliably, when I put the listener setup into this set of 3 scripts:
-------- snip rclistener ----------------
% cat /etc/init.d/rclistener
#!/bin/bash
case $1 in
'start')
/usr/local/bin/listener-watchdog &
sleep 1
$0 status
;;
'stop')
lpid=$(ps aux|grep "/bin/bash /usr/local/bin/listener-watchdog"|grep -v grep|awk '{print $2}')
if [[ -n ${lpid} ]]; then
kill ${lpid}
fi
sleep 1
$0 status
;;
'status')
lpid=$(ps aux|grep "/bin/bash /usr/local/bin/listener-watchdog"|grep -v grep|awk '{print $2}')
if [[ -n ${lpid} ]]; then
echo "netcat listener watchdog is running with PID ${lpid}"
else
echo "no netcat listener running."
fi
;;
*)
echo "Usage: $0 start|stop|status"
;;
esac
-------- snap ----------------
Note, how the startscript needs to put the "listener-watchdog" into the background, otherwise it would not return immediately.
The watchdog is creating a "while true; ...; done" loop the netcat listener to run in:
-------- snip listener-watchdog ----------------
% cat /usr/local/bin/listener-watchdog
#!/bin/bash
while true; do
/usr/local/bin/listener-wrapper
done
-------- snap ----------------
Finally, the wrapper itself. It
-------- snip listener-wrapper ----------------
% cat /usr/local/bin/listener-wrapper
#!/bin/bash
now=$(date +%s)
netcat -l -v -v -w 3600 -n -s 11.12.13.14 -p 9111 \
2>>/var/log/cups/netcat_err.log \
| gzip - \
> /var/spool/netcat/${now}.prn \
&& gzip /var/spool/netcat/${now}.prn
sleep 1;
-------- snap ----------------
Now the problem is this: when I send small files, everything works fine. When I send big ones (like above, chunks of 512,000,000 Bytes), they get truncated at arbitrary multiples of 8192 Bytes. See this log extract:
(UNKNOWN) [11.12.13.14] 22222 (?) open
sent 8192, rcvd 0
(UNKNOWN) [11.12.13.14] 22222 (?) open
sent 196608, rcvd 0
(UNKNOWN) [11.12.13.14] 22222 (?) open
sent 189440, rcvd 0
(UNKNOWN) [11.12.13.14] 22222 (?) open
sent 73728, rcvd 0
(UNKNOWN) [11.12.13.14] 22222 (?) open
sent 8192, rcvd 0
If I remove the "&" from the listener-watchdog call in the "rc-listener" startup script, that script does not return the shell console to me. However, if I use "^Z;bg" to put it into the background, it works perfectly, and all data arrive without fail.
I'm at my wits' end. It seems to be connected to the mentioned backgrounding of the "listener-watchdog" call inside the "rclistener" script.
Why...
...does putting that one line directly into the background inside
the script *not* work,
...while calling it normally, but instead putting the whole script
manually into the background work
????
More information about the cups
mailing list