The lpd included in the RedHat "lpr" package cannot accept jobs from Macintosh computers using the "LaserWriter" extension which supports the lpr protocol. There are two problems which prevent it from accepting these files; one of them is a bug in the LaserWriter extension (which I've already reported to Apple), and another is a bug in lpd. The patch below fixes the bug in lpd, introduces a workaround for the bug in the LaserWriter extension, and fixes an additional bug. In particular: 1) In lpd.c, set the SO_REUSEADDR socket option on the lpd socket before binding it, so that it's possible to run lpd immediately after "kill -9"ing it. There's really no good reason why any TCP/IP application server shouldn't set SO_REUSEADDR. This is the "additional bug" mentioned above. I discovered it while debugging the other problems. 2) In recvjob.c, detect when we receive a null immediately after receiving a file from the client, and if that happens, discard it. This is necessary because the LPR protocol specifies that the client should send a null immediately after sending the contents of a control or data file. I can only assume that other lpr clients don't bother to send the null (i.e., they are not compliant with the RFC), otherwise lpd would have run into this problem with other clients besides the LaserWriter extension. In any case, this change is backward compatible to clients that don't send the null. 3) In recvjob.c, notice if the client sends the print queue name twice, and if so, discard the second one. For some reason, the LaserWriter extension sends the "receive job" command twice. I've reported this to Apple as a bug, but in the meantime, this workaround will make lpd accept jobs despite the duplicate command. Only in lpr-0.46.new/lpd: TAGS diff -ur lpr-0.46/lpd/lpd.c lpr-0.46.new/lpd/lpd.c --- lpr-0.46/lpd/lpd.c Fri Oct 22 16:44:35 1999 +++ lpr-0.46.new/lpd/lpd.c Sat Dec 4 23:27:59 1999 @@ -167,6 +167,10 @@ finet = socket(AF_INET, SOCK_STREAM, 0); if (finet >= 0) { struct servent *sp; + int val = 1; + + (void) setsockopt(finet, SOL_SOCKET, SO_REUSEADDR, &val, + sizeof(val)); if (options & SO_DEBUG) if (setsockopt(finet, SOL_SOCKET, SO_DEBUG, 0, 0) < 0) { diff -ur lpr-0.46/lpd/recvjob.c lpr-0.46.new/lpd/recvjob.c --- lpr-0.46/lpd/recvjob.c Sat Oct 23 01:50:39 1999 +++ lpr-0.46.new/lpd/recvjob.c Sun Dec 5 00:05:36 1999 @@ -118,6 +118,7 @@ struct passwd *user; struct group *lpgrp; FILE *cfile; + int gotfile = 0; /* Did we just receive a control or data file? */ lpgrp = getgrnam("lp"); ack(); @@ -141,12 +142,26 @@ } while (*cp++ != '\n' && (cp - line + 1) < sizeof(line)); *--cp = '\0'; cp = line; + if (gotfile && (*cp == '\0')) { + /* The protocol says that data files should be + terminated by a null octet. */ + cp++; + } + gotfile = 0; switch (*cp++) { case '\1': /* cleanup because data sent was bad */ rcleanup(); continue; case '\2': /* read cf file */ + if (! strcmp(cp, printer)) { + /* MacOS LaserWriter 8.7 lpr client + sends the printer "recvjob" command + twice. */ + ack(); + continue; + } + gotfile = 1; user = getpwnam("lp"); size = 0; while (*cp >= '0' && *cp <= '9') @@ -201,6 +216,7 @@ continue; case '\3': /* read df file */ + gotfile = 1; size = 0; while (*cp >= '0' && *cp <= '9') size = size * 10 + (*cp++ - '0');
Created attachment 108 [details] new patch for lpr-0.50
Thanks - I've added it to the lpr cvs tree for the next base version (0.51).