[offtopic] Incomplete data received with scripted netcat that emulates a JetDirect printjob receiver

Kurt Pfeifle kurt.pfeifle at infotec.com
Sat Jun 7 20:48:47 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

You can also use

      ifconfig lo: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

Actually, above output comes from an experiment that I did on Port 22222 (not 9111 as used in the script). But the result was the same in either case.

> 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