Blob


1 #ifdef plan9
3 #include <u.h>
4 #include <libc.h>
5 #define stderr 2
7 #define RDNETIMEOUT 60000
8 #define WRNETIMEOUT 60000
10 #else
12 /* not for plan 9 */
13 #include <stdio.h>
14 #include <errno.h>
15 #include <time.h>
16 #include <fcntl.h>
17 #include <signal.h>
19 #define create creat
20 #define seek lseek
21 #define fprint fprintf
22 #define sprint sprintf
23 #define exits exit
25 #define ORDWR O_RDWR
26 #define OTRUNC O_TRUNC
27 #define ORCLOSE 0
29 #define RDNETIMEOUT 60
30 #define WRNETIMEOUT 60
32 #endif
34 #define MIN(a,b) ((a<b)?a:b)
36 #define ACK(a) write(a, "", 1)
37 #define NAK(a) write(a, "\001", 1)
39 #define LPDAEMONLOG "/tmp/lpdaemonl"
41 #define LNBFSZ 4096
42 char lnbuf[LNBFSZ];
43 int dbgstate = 0;
44 char *dbgstrings[] = {
45 "",
46 "rcvack1",
47 "send",
48 "rcvack2",
49 "response",
50 "done"
51 };
53 #ifdef plan9
55 void
56 error(int level, char *s1, ...)
57 {
58 va_list ap;
59 long thetime;
60 char *chartime;
61 char *args[8];
62 int argno = 0;
64 if (level == 0) {
65 time(&thetime);
66 chartime = ctime(thetime);
67 fprint(stderr, "%.15s ", &(chartime[4]));
68 }
69 va_start(ap, s1);
70 while(args[argno++] = va_arg(ap, char*));
71 va_end(ap);
72 fprint(stderr, s1, *args);
73 return;
74 }
76 int
77 alarmhandler(void *foo, char *note) {
78 USED(foo);
79 if(strcmp(note, "alarm")==0) {
80 fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
81 return(1);
82 } else return(0);
83 }
85 #else
87 void
88 error(int level, char *s1, ...)
89 {
90 time_t thetime;
91 char *chartime;
93 if (level == 0) {
94 time(&thetime);
95 chartime = ctime(&thetime);
96 fprintf(stderr, "%.15s ", &(chartime[4]));
97 }
98 fprintf(stderr, s1, (&s1+1));
99 return;
102 void
103 alarmhandler() {
104 fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
107 #endif
109 /* get a line from inpfd using nonbuffered input. The line is truncated if it is too
110 * long for the buffer. The result is left in lnbuf and the number of characters
111 * read in is returned.
112 */
113 int
114 readline(int inpfd)
116 register char *ap;
117 register int i;
119 ap = lnbuf;
120 i = 0;
121 do {
122 if (read(inpfd, ap, 1) != 1) {
123 error(0, "read error in readline, fd=%d\n", inpfd);
124 break;
126 } while ((++i < LNBFSZ - 2) && *ap++ != '\n');
127 if (i == LNBFSZ - 2) {
128 *ap = '\n';
129 i++;
131 *ap = '\0';
132 return(i);
135 #define RDSIZE 512
136 char jobbuf[RDSIZE];
138 int
139 pass(int inpfd, int outfd, int bsize)
141 int bcnt = 0;
142 int rv = 0;
144 for(bcnt=bsize; bcnt > 0; bcnt -= rv) {
145 alarm(WRNETIMEOUT); /* to break hanging */
146 if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
147 error(0, "read error during pass, %d remaining\n", bcnt);
148 break;
149 } else if((write(outfd, jobbuf, rv)) != rv) {
150 error(0, "write error during pass, %d remaining\n", bcnt);
151 break;
154 alarm(0);
155 return(bcnt);
158 /* get whatever stdin has and put it into the temporary file.
159 * return the file size.
160 */
161 int
162 prereadfile(int inpfd)
164 int rv, bsize;
166 bsize = 0;
167 do {
168 if((rv=read(0, jobbuf, RDSIZE))<0) {
169 error(0, "read error while making temp file\n");
170 exits("read error while making temp file");
171 } else if((write(inpfd, jobbuf, rv)) != rv) {
172 error(0, "write error while making temp file\n");
173 exits("write error while making temp file");
175 bsize += rv;
176 } while (rv!=0);
177 return(bsize);
180 int
181 tempfile(void)
183 static int tindx = 0;
184 char tmpf[20];
185 int tmpfd;
187 sprint(tmpf, "/var/tmp/lp%d.%d", getpid(), tindx++);
188 if((tmpfd=create(tmpf,
190 #ifdef plan9
192 ORDWR|OTRUNC,
194 #endif
196 0666)) < 0) {
197 error(0, "cannot create temp file %s\n", tmpf);
198 exits("cannot create temp file");
200 close(tmpfd);
201 if((tmpfd=open(tmpf, ORDWR
203 #ifdef plan9
205 |ORCLOSE|OTRUNC
207 #endif
209 )) < 0) {
210 error(0, "cannot open temp file %s\n", tmpf);
211 exits("cannot open temp file");
213 return(tmpfd);
216 int
217 recvACK(int netfd)
219 int rv;
221 *jobbuf = '\0';
222 alarm(RDNETIMEOUT);
223 if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
224 error(0, "failed to receive ACK, ");
225 if (*jobbuf == '\0')
226 error(1, "read failed\n");
227 else
228 error(1, "received <0x%x> instead\n", *jobbuf);
229 rv = 0;
230 } else rv = 1;
231 alarm(0);
232 return(rv);
235 void
236 main(int argc, char *argv[])
238 char *devdir;
239 int i, rv, netfd, bsize;
240 int datafd;
242 #ifndef plan9
244 void (*oldhandler)();
246 #endif
248 devdir = nil;
249 /* make connection */
250 if (argc != 2) {
251 fprint(stderr, "usage: %s network!destination!service\n", argv[0]);
252 exits("incorrect number of arguments");
255 /* read options line from stdin into lnbuf */
256 i = readline(0);
258 /* read stdin into tempfile to get size */
259 datafd = tempfile();
260 bsize = prereadfile(datafd);
262 /* network connection is opened after data is in to avoid timeout */
263 if ((netfd=dial(argv[1], 0, 0, 0)) < 0) {
264 fprint(stderr, "dialing %s\n", devdir);
265 perror("dial");
266 exits("can't dial");
269 /* write out the options we read above */
270 if (write(netfd, lnbuf, i) != i) {
271 error(0, "write error while sending options\n");
272 exits("write error while sending options");
275 /* send the size of the file to be sent */
276 sprint(lnbuf, "%d\n", bsize);
277 i = strlen(lnbuf);
278 if ((rv=write(netfd, lnbuf, i)) != i) {
279 perror("write error while sending size");
280 error(0, "write returned %d\n", rv);
281 exits("write error while sending size");
284 if (seek(datafd, 0L, 0) < 0) {
285 error(0, "error seeking temp file\n");
286 exits("seek error");
288 /* mirror performance in readfile() in lpdaemon */
290 #ifdef plan9
292 atnotify(alarmhandler, 1);
294 #else
296 oldhandler = signal(SIGALRM, alarmhandler);
298 #endif
300 dbgstate = 1;
301 if(!recvACK(netfd)) {
302 error(0, "failed to receive ACK before sending data\n");
303 exits("recv ack1 failed");
305 dbgstate = 2;
306 if ((i=pass(datafd, netfd, bsize)) != 0) {
307 NAK(netfd);
308 error(0, "failed to send %d bytes\n", i);
309 exits("send data failed");
311 ACK(netfd);
312 dbgstate = 3;
313 if(!recvACK(netfd)) {
314 error(0, "failed to receive ACK after sending data\n");
315 exits("recv ack2 failed");
318 /* get response, as from lp -q */
319 dbgstate = 4;
320 while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
321 if((write(1, jobbuf, rv)) != rv) {
322 error(0, "write error while sending to stdout\n");
323 exits("write error while sending to stdout");
326 dbgstate = 5;
328 #ifdef plan9
330 atnotify(alarmhandler, 0);
331 /* close down network connections and go away */
332 exits("");
334 #else
336 signal(SIGALRM, oldhandler);
337 exit(0);
339 #endif