1 | #ifndef lint |
---|
2 | #define _NOTICE static char |
---|
3 | _NOTICE N1[] = "Copyright (c) 1993 Adobe Systems Incorporated"; |
---|
4 | _NOTICE RCSID[] = "$Header: /afs/dev.mit.edu/source/repository/third/transcript/src/ascomm.c,v 1.1.1.1 1996-10-07 20:25:47 ghudson Exp $"; |
---|
5 | #endif |
---|
6 | /* |
---|
7 | * ascomm.c |
---|
8 | * |
---|
9 | * Copyright (C) 1993 Adobe Systems Incorporated. |
---|
10 | * All rights reserved. |
---|
11 | * |
---|
12 | * lpr/lpd communications filter for Adobe network printer. |
---|
13 | * |
---|
14 | * ascomm gets called with: |
---|
15 | * stdin = the file to print |
---|
16 | * stdout = the printer device (ignored) |
---|
17 | * stderr = the printer log file |
---|
18 | * cwd = the spool directory |
---|
19 | * argv = set up by interface shell script: |
---|
20 | * filtername -P printer -p filtername -n username -h host [acctfile] |
---|
21 | * |
---|
22 | * |
---|
23 | */ |
---|
24 | /* |
---|
25 | RCSLOG |
---|
26 | $Log: not supported by cvs2svn $ |
---|
27 | * Revision 1.6 1994/04/08 23:27:38 snichols |
---|
28 | * added sigignore for SIGPIPE, surrounded by ifdef SYSV since |
---|
29 | * not all BSD systems have sigignore, and the problem doesn't |
---|
30 | * happen there anyway. |
---|
31 | * |
---|
32 | * Revision 1.5 1994/04/08 23:15:14 snichols |
---|
33 | * more fixes for Solaris. |
---|
34 | * |
---|
35 | * Revision 1.4 1994/04/08 21:03:25 snichols |
---|
36 | * close fdinput as soon as we're done with it, to avoid SIGPIPE problems |
---|
37 | * on Solaris. |
---|
38 | * |
---|
39 | * Revision 1.3 1994/03/09 18:15:32 snichols |
---|
40 | * added support for not using the control protocol and not querying status. |
---|
41 | * |
---|
42 | * Revision 1.2 1994/02/16 22:41:54 snichols |
---|
43 | * ported to Solaris, plus some typos corrected. |
---|
44 | * |
---|
45 | */ |
---|
46 | |
---|
47 | #include <stdlib.h> |
---|
48 | #include <stdio.h> |
---|
49 | #include <unistd.h> |
---|
50 | #include <fcntl.h> |
---|
51 | #include <signal.h> |
---|
52 | #include <sys/time.h> |
---|
53 | #include <sys/wait.h> |
---|
54 | #include <netdb.h> |
---|
55 | #include <sys/types.h> |
---|
56 | #include <sys/socket.h> |
---|
57 | #include <netinet/in.h> |
---|
58 | #include <errno.h> |
---|
59 | #include <netinet/tcp.h> |
---|
60 | #include <string.h> |
---|
61 | |
---|
62 | #include "transcript.h" |
---|
63 | #include "config.h" |
---|
64 | |
---|
65 | #define TRUE 1 |
---|
66 | #define FALSE 0 |
---|
67 | |
---|
68 | |
---|
69 | static char *prog ="ascomm"; |
---|
70 | static char *host = " "; |
---|
71 | static char *name = " "; |
---|
72 | static char *pname = " "; |
---|
73 | static char *accountingfile; |
---|
74 | |
---|
75 | static long startpagecount; |
---|
76 | static long endpagecount; |
---|
77 | |
---|
78 | static char *getpages = "(%%[ pagecount: )print statusdict/pagecount \ |
---|
79 | get exec ( ) cvs print ( ]%%)= flush"; |
---|
80 | |
---|
81 | static int socklen; |
---|
82 | static struct sockaddr_in datasock; |
---|
83 | static struct sockaddr_in statussock; |
---|
84 | static struct sockaddr_in self; |
---|
85 | static struct hostent *hp; |
---|
86 | |
---|
87 | static char *hostname; |
---|
88 | static int ppid; |
---|
89 | |
---|
90 | static int fdsend; |
---|
91 | static int fdinput; |
---|
92 | static int fdcontrol; |
---|
93 | static int fdstatus; |
---|
94 | |
---|
95 | int control = 1; |
---|
96 | int status = 1; |
---|
97 | |
---|
98 | struct controlpacket { |
---|
99 | unsigned char ctrlchar; |
---|
100 | unsigned char dummy; |
---|
101 | u_short port; |
---|
102 | } controldata; |
---|
103 | |
---|
104 | static fd_set readfds; |
---|
105 | static fd_set statfds; |
---|
106 | |
---|
107 | static int doactng; |
---|
108 | static int bannerfirst = 0; |
---|
109 | static int bannerlast = 0; |
---|
110 | |
---|
111 | |
---|
112 | /* job state variables */ |
---|
113 | typedef enum { |
---|
114 | init, /* initialization */ |
---|
115 | syncstart, /* first acc'ting job */ |
---|
116 | sending, /* sending main job to printer */ |
---|
117 | waiting, /* waiting for EOF from printer */ |
---|
118 | lastpart, /* sending banner after job */ |
---|
119 | synclast, /* last acc'ting job */ |
---|
120 | ending, /* cleaning up */ |
---|
121 | croaking, /* abnormal exit */ |
---|
122 | child, /* child */ |
---|
123 | } states; |
---|
124 | |
---|
125 | static states currentstate; |
---|
126 | |
---|
127 | static int statusp; |
---|
128 | |
---|
129 | static void JobControl(); |
---|
130 | |
---|
131 | #define PRINTER_PORT 9100 |
---|
132 | #define STATUS_PORT 9101 |
---|
133 | #define MYBUFSIZE 10240 |
---|
134 | |
---|
135 | #ifdef BDEBUG |
---|
136 | #define debugp(x) {fprintf x ; (void) fflush(stderr);} |
---|
137 | extern int errno; |
---|
138 | #else |
---|
139 | #define debugp(x) |
---|
140 | #endif /* BDEBUG */ |
---|
141 | |
---|
142 | static int dataport = PRINTER_PORT; |
---|
143 | static int statusport = STATUS_PORT; |
---|
144 | static int localport; |
---|
145 | |
---|
146 | static void cleanupandexit(code) |
---|
147 | int code; |
---|
148 | { |
---|
149 | /* we want to clean and and leave; closing any open file descriptors, |
---|
150 | and possibly trying to send an end of session to the printer */ |
---|
151 | |
---|
152 | debugp((stderr, "cleanupanexit send %d status %d control %d\n", fdsend, |
---|
153 | fdstatus, fdcontrol)); |
---|
154 | if (currentstate >= syncstart && currentstate < ending) { |
---|
155 | /* send a ctrl-D to clean up */ |
---|
156 | controldata.ctrlchar = 0x04; |
---|
157 | controldata.port = htons(0); |
---|
158 | JobControl(controldata); |
---|
159 | |
---|
160 | } |
---|
161 | if (fdsend) close(fdsend); |
---|
162 | if (fdinput) close(fdinput); |
---|
163 | if (fdstatus) close(fdstatus); |
---|
164 | if (fdcontrol) close(fdcontrol); |
---|
165 | exit(code); |
---|
166 | } |
---|
167 | |
---|
168 | #ifdef BDEBUG |
---|
169 | handler(sig) |
---|
170 | int sig; |
---|
171 | { |
---|
172 | char buf[20]; |
---|
173 | sprintf(buf, "terminated with signal %d\n", sig); |
---|
174 | write(2,buf, strlen(buf)); |
---|
175 | _exit(2); |
---|
176 | } |
---|
177 | #endif |
---|
178 | |
---|
179 | static void giveup(sig) |
---|
180 | int sig; |
---|
181 | { |
---|
182 | /* child told us to die */ |
---|
183 | debugp((stderr, "Got EMT sig! Die!.\n")); |
---|
184 | cleanupandexit(2); |
---|
185 | } |
---|
186 | |
---|
187 | static long ParseAnswer(p) |
---|
188 | char *p; |
---|
189 | { |
---|
190 | char *r; |
---|
191 | char *q; |
---|
192 | |
---|
193 | r = strchr(p, ':'); |
---|
194 | if (r == NULL) |
---|
195 | return 0; |
---|
196 | r++; |
---|
197 | while (*r == ' ') r++; |
---|
198 | /* now r should point to count */ |
---|
199 | q = strchr(r, ' '); |
---|
200 | if (q == NULL) |
---|
201 | return 0; |
---|
202 | *q = '\0'; |
---|
203 | return atoi(r); |
---|
204 | } |
---|
205 | |
---|
206 | static void AccountingJob(pagecount) |
---|
207 | long *pagecount; |
---|
208 | { |
---|
209 | int cnt; |
---|
210 | char buf[BUFSIZ]; |
---|
211 | int foo; |
---|
212 | int r; |
---|
213 | int percents = 0; |
---|
214 | struct linger linger; |
---|
215 | char *p; |
---|
216 | |
---|
217 | /* NOTE: this closes the connection! */ |
---|
218 | |
---|
219 | foo = 1; |
---|
220 | if (setsockopt(fdsend, IPPROTO_TCP, TCP_NODELAY, (char *)&foo, |
---|
221 | sizeof(foo)) < 0) { |
---|
222 | perror("sockcomm: setsockopt (no delay)"); |
---|
223 | cleanupandexit(2); |
---|
224 | } |
---|
225 | |
---|
226 | debugp((stderr, "sending accounting job\n")); |
---|
227 | cnt = write(fdsend, getpages, strlen(getpages)); |
---|
228 | linger.l_onoff = 0; |
---|
229 | linger.l_linger = 0; |
---|
230 | if (setsockopt(fdsend, SOL_SOCKET, SO_LINGER, (char *)&linger, |
---|
231 | sizeof(linger)) |
---|
232 | < 0) { |
---|
233 | perror("sockcomm: setsockopt(linger)"); |
---|
234 | cleanupandexit(2); |
---|
235 | } |
---|
236 | shutdown(fdsend, 1); |
---|
237 | debugp((stderr, "sent %d bytes\n", cnt)); |
---|
238 | p = buf; |
---|
239 | while ((cnt = read(fdsend, p, BUFSIZ)) > 0) { |
---|
240 | p += cnt; |
---|
241 | } |
---|
242 | *p = '\0'; |
---|
243 | debugp((stderr, "%s\n", buf)); |
---|
244 | *pagecount = ParseAnswer(buf); |
---|
245 | close(fdsend); |
---|
246 | } |
---|
247 | |
---|
248 | static void AcctEntry(start, end) |
---|
249 | long start, end; |
---|
250 | { |
---|
251 | FILE *fp; |
---|
252 | |
---|
253 | debugp((stderr, "startpagecount %d endpagecount %d\n", startpagecount, |
---|
254 | endpagecount)); |
---|
255 | if (start > end || start < 0 || end < 0) { |
---|
256 | fprintf(stderr, "%s: accounting error: start %d end %d\n", prog, |
---|
257 | start, end); |
---|
258 | fflush(stderr); |
---|
259 | } |
---|
260 | else if ((fp = fopen(accountingfile, "a")) != NULL) { |
---|
261 | fprintf(fp, "%7.2f\t%s:%s\n", (float) (end - start), host, name); |
---|
262 | fclose(fp); |
---|
263 | } |
---|
264 | } |
---|
265 | |
---|
266 | |
---|
267 | |
---|
268 | static void ReopenConn() |
---|
269 | { |
---|
270 | struct linger linger; |
---|
271 | struct sockaddr_in sockname; |
---|
272 | int namelen = sizeof(struct sockaddr_in); |
---|
273 | |
---|
274 | if ((fdsend = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
---|
275 | fprintf(stderr, "%s: error creating data socket\n", prog); |
---|
276 | cleanupandexit(2); |
---|
277 | } |
---|
278 | debugp((stderr, "after data socket call\n")); |
---|
279 | debugp((stderr, "TCP file descriptor (data) %d\n", fdsend)); |
---|
280 | |
---|
281 | linger.l_onoff = 1; |
---|
282 | linger.l_linger = 0; |
---|
283 | if (setsockopt(fdsend, SOL_SOCKET, SO_LINGER, (char *)&linger, |
---|
284 | sizeof(linger)) |
---|
285 | < 0) { |
---|
286 | perror("sockcomm: setsockopt(linger)"); |
---|
287 | cleanupandexit(2); |
---|
288 | } |
---|
289 | |
---|
290 | memset(&self, 0, sizeof(self)); |
---|
291 | self.sin_addr.s_addr = htonl(INADDR_ANY); |
---|
292 | self.sin_family = AF_INET; |
---|
293 | self.sin_port = htons(0); |
---|
294 | if (bind(fdsend, (struct sockaddr *)&self, sizeof(self)) < 0) { |
---|
295 | fprintf(stderr, "%s: bind of local address failed (data)\n", prog); |
---|
296 | cleanupandexit(2); |
---|
297 | } |
---|
298 | getsockname(fdsend, (struct sockaddr *)&sockname, &namelen); |
---|
299 | debugp((stderr, "local port is %d\n", sockname.sin_port)); |
---|
300 | localport = sockname.sin_port; |
---|
301 | controldata.ctrlchar = 0x02; |
---|
302 | controldata.port = localport; |
---|
303 | JobControl(controldata); |
---|
304 | |
---|
305 | while (1) { |
---|
306 | if (connect(fdsend, (struct sockaddr *)&datasock, socklen) < 0) { |
---|
307 | continue; |
---|
308 | } |
---|
309 | break; |
---|
310 | } |
---|
311 | } |
---|
312 | |
---|
313 | static void SendBanner(done) |
---|
314 | int done; |
---|
315 | { |
---|
316 | int banner; |
---|
317 | int cnt; |
---|
318 | char buf[MYBUFSIZE]; |
---|
319 | |
---|
320 | debugp((stderr, "in SendBanner\n")); |
---|
321 | if ((banner = open(".banner", O_RDONLY|O_NDELAY, 0)) < 0) { |
---|
322 | fprintf(stderr, "%s: no banner file\n", prog); |
---|
323 | return; |
---|
324 | } |
---|
325 | while ((cnt = read(banner, buf, sizeof(buf))) > 0) { |
---|
326 | debugp((stderr, "read %d bytes for banner.\n", cnt)); |
---|
327 | write(fdsend, buf, cnt); |
---|
328 | } |
---|
329 | /* hang around until banner is done */ |
---|
330 | if (done) { |
---|
331 | shutdown(fdsend, 1); |
---|
332 | while ((cnt = read(fdsend, buf, sizeof(buf))) > 0); |
---|
333 | } |
---|
334 | close(banner); |
---|
335 | } |
---|
336 | |
---|
337 | |
---|
338 | static int CheckStatus(who) |
---|
339 | char *who; |
---|
340 | { |
---|
341 | /* send a packet down a UDP port to the printer; expect |
---|
342 | interpreter status in return */ |
---|
343 | |
---|
344 | char readbuf[MYBUFSIZE]; |
---|
345 | int nfound = 0; |
---|
346 | int cnt; |
---|
347 | int retries = 0; |
---|
348 | struct sockaddr from; |
---|
349 | int fromlen; |
---|
350 | int answered = FALSE; |
---|
351 | struct timeval timeout; |
---|
352 | |
---|
353 | if (!status) { |
---|
354 | return 1; |
---|
355 | } |
---|
356 | /* set up select */ |
---|
357 | FD_ZERO(&statfds); |
---|
358 | FD_SET(fdstatus, &statfds); |
---|
359 | timeout.tv_sec = 5; |
---|
360 | timeout.tv_usec = 0; |
---|
361 | |
---|
362 | cnt = sendto(fdstatus, " ", 1, 0, (struct sockaddr *)&statussock, |
---|
363 | sizeof(statussock)); |
---|
364 | debugp((stderr, "%s: sent status query\n", who)); |
---|
365 | |
---|
366 | while (1) { |
---|
367 | nfound = select(fdstatus+1, &statfds, (fd_set *) 0, (fd_set *) 0, |
---|
368 | &timeout); |
---|
369 | if (nfound > 0) { |
---|
370 | cnt = recvfrom(fdstatus, readbuf, MYBUFSIZE, 0, |
---|
371 | (struct sockaddr *)&from, (int *) &fromlen); |
---|
372 | if (cnt > 0) { |
---|
373 | debugp((stderr, "%s: fdstatus read cnt %d\n", who, cnt)); |
---|
374 | readbuf[cnt] = '\0'; |
---|
375 | debugp((stderr, "stat: %s\n", readbuf)); |
---|
376 | answered = TRUE; |
---|
377 | } |
---|
378 | else if (cnt == 0) { |
---|
379 | break; |
---|
380 | } |
---|
381 | else { |
---|
382 | fprintf(stderr, "%s: fatal error reading status\n", prog); |
---|
383 | perror(""); |
---|
384 | return -1; |
---|
385 | } |
---|
386 | } |
---|
387 | else if (nfound == 0) { |
---|
388 | if (answered) { |
---|
389 | /* we received an answer, so this timeout probably means |
---|
390 | we're done receiving this answer */ |
---|
391 | break; |
---|
392 | } |
---|
393 | debugp((stderr, |
---|
394 | "checkstatus: no response from printer, retrying %d.\n", |
---|
395 | ++retries)); |
---|
396 | if (retries > 3) { |
---|
397 | fprintf(stderr, |
---|
398 | "%s: no response from printer! giving up.\n", prog); |
---|
399 | return 0; |
---|
400 | } |
---|
401 | cnt = sendto(fdstatus, "\024", 1, 0, (struct sockaddr *)&statussock, |
---|
402 | sizeof(statussock)); |
---|
403 | FD_ZERO(&statfds); |
---|
404 | FD_SET(fdstatus, &statfds); |
---|
405 | timeout.tv_sec = 5; |
---|
406 | timeout.tv_usec = 0; |
---|
407 | } |
---|
408 | } |
---|
409 | return 1; |
---|
410 | } |
---|
411 | |
---|
412 | static void Listener() |
---|
413 | { |
---|
414 | /* child process; listens to the data port. When |
---|
415 | it receives EOF on the data port, it exits. */ |
---|
416 | |
---|
417 | static char readbuf[MYBUFSIZE]; |
---|
418 | int cs, done = FALSE; |
---|
419 | int nfound = 0; |
---|
420 | int cnt; |
---|
421 | struct timeval timeout; |
---|
422 | |
---|
423 | /* child */ |
---|
424 | debugp((stderr, "child started\n")); |
---|
425 | |
---|
426 | while (!done) { |
---|
427 | debugp((stderr, "child: calling select\n")); |
---|
428 | |
---|
429 | /* set up select so we can listen on data sockets */ |
---|
430 | |
---|
431 | FD_ZERO(&readfds); |
---|
432 | FD_SET(fdsend, &readfds); |
---|
433 | |
---|
434 | timeout.tv_sec = 15; |
---|
435 | timeout.tv_usec = 0; |
---|
436 | nfound = select(fdsend+1, &readfds, (fd_set *) 0, |
---|
437 | (fd_set *) 0, &timeout); |
---|
438 | if (nfound < 0 || nfound > 2) { |
---|
439 | /* select failed */ |
---|
440 | fprintf(stderr, "%s: select failed\n", prog); |
---|
441 | perror(""); |
---|
442 | kill(ppid, SIGEMT); |
---|
443 | cleanupandexit(2); |
---|
444 | } |
---|
445 | else { |
---|
446 | if (nfound == 0) { |
---|
447 | /* timeout! */ |
---|
448 | debugp((stderr,"child: timeout\n")); |
---|
449 | cs = CheckStatus("child"); |
---|
450 | if (cs < 1) { |
---|
451 | fprintf(stderr, "Giving up!\n"); |
---|
452 | kill(ppid, SIGEMT); |
---|
453 | cleanupandexit(2); |
---|
454 | } |
---|
455 | } |
---|
456 | if (nfound > 0) { |
---|
457 | debugp((stderr, "child: data ready! %d\n", nfound)); |
---|
458 | /* data ready! */ |
---|
459 | if (FD_ISSET(fdsend, &readfds)) { |
---|
460 | debugp((stderr, "child: data ready on fdsend\n")); |
---|
461 | cnt = read(fdsend, readbuf, MYBUFSIZE); |
---|
462 | debugp((stderr, "child: fdsend read cnt %d\n", |
---|
463 | cnt)); |
---|
464 | if (cnt < 0) { |
---|
465 | fprintf(stderr, |
---|
466 | "%s: fatal error reading from data port!\n", |
---|
467 | prog); |
---|
468 | perror(""); |
---|
469 | kill(ppid, SIGEMT); |
---|
470 | cleanupandexit(2); |
---|
471 | } |
---|
472 | readbuf[cnt] = '\0'; |
---|
473 | if (cnt > 0) { |
---|
474 | fprintf(stderr, "%s", readbuf); |
---|
475 | } |
---|
476 | else { |
---|
477 | done = TRUE; |
---|
478 | break; |
---|
479 | } |
---|
480 | } |
---|
481 | } |
---|
482 | } |
---|
483 | } |
---|
484 | cleanupandexit(2); |
---|
485 | } |
---|
486 | |
---|
487 | static void JobControl(msg) |
---|
488 | struct controlpacket msg; |
---|
489 | { |
---|
490 | /* sends msg as a TCP packet down the control port, listens for |
---|
491 | response; this will change to TCP */ |
---|
492 | int cnt; |
---|
493 | int nfound = 0; |
---|
494 | char readbuf[MYBUFSIZE]; |
---|
495 | int retries = 0; |
---|
496 | struct sockaddr from; |
---|
497 | int fromlen; |
---|
498 | char *p; |
---|
499 | |
---|
500 | if (!control) { |
---|
501 | /* if we're not doing job control, bail */ |
---|
502 | return; |
---|
503 | } |
---|
504 | /* send msg */ |
---|
505 | cnt = write(fdcontrol, &msg, sizeof(msg)); |
---|
506 | debugp((stderr, "%d: sent %x\n", currentstate, msg.ctrlchar)); |
---|
507 | cnt = read(fdcontrol, readbuf, sizeof(readbuf)); |
---|
508 | if (cnt > 0) { |
---|
509 | debugp((stderr, "%d: received %x\n", currentstate, readbuf[0])); |
---|
510 | if (readbuf[0] != msg.ctrlchar) { |
---|
511 | fprintf(stderr, "%s: unexpected response from printer!\n", prog); |
---|
512 | cleanupandexit(2); |
---|
513 | } |
---|
514 | } |
---|
515 | } |
---|
516 | |
---|
517 | |
---|
518 | static void abortjob(sig) |
---|
519 | int sig; |
---|
520 | { |
---|
521 | debugp((stderr, "%s: Got 'die' signal=%d, state=%d\n", prog, sig, |
---|
522 | currentstate)); |
---|
523 | controldata.ctrlchar = 0x03; |
---|
524 | controldata.port = htons(0); |
---|
525 | switch (currentstate) { |
---|
526 | case init: |
---|
527 | cleanupandexit(2); |
---|
528 | break; |
---|
529 | case syncstart: |
---|
530 | fprintf(stderr, "%s: abort (start communications)\n", prog); |
---|
531 | fflush(stderr); |
---|
532 | JobControl(controldata); |
---|
533 | cleanupandexit(2); |
---|
534 | break; |
---|
535 | case sending: |
---|
536 | fprintf(stderr, "%s: abort (sending job)\n", prog); |
---|
537 | fflush(stderr); |
---|
538 | JobControl(controldata); |
---|
539 | cleanupandexit(2); |
---|
540 | break; |
---|
541 | case lastpart: |
---|
542 | case synclast: |
---|
543 | fprintf(stderr, "%s: abort (post-job processing)\n", prog); |
---|
544 | fflush(stderr); |
---|
545 | JobControl(controldata); |
---|
546 | cleanupandexit(2); |
---|
547 | break; |
---|
548 | default: |
---|
549 | break; |
---|
550 | } |
---|
551 | } |
---|
552 | |
---|
553 | static void SendFile() |
---|
554 | { |
---|
555 | int cnt, wc; |
---|
556 | char *mbp; |
---|
557 | char mybuf[MYBUFSIZE]; |
---|
558 | int pid, childpid; |
---|
559 | char readbuf[MYBUFSIZE]; |
---|
560 | int foo = 1; |
---|
561 | int retries = 0; |
---|
562 | struct sockaddr_in sockname; |
---|
563 | int namelen = sizeof(struct sockaddr_in); |
---|
564 | struct linger linger; |
---|
565 | |
---|
566 | /* create status, control, and data connectons */ |
---|
567 | if ((fdstatus = socket(AF_INET, SOCK_DGRAM, 0)) < 0) { |
---|
568 | fprintf(stderr, "%s: error creating status socket.\n", prog); |
---|
569 | perror(""); |
---|
570 | cleanupandexit(2); |
---|
571 | } |
---|
572 | debugp((stderr, "after status socket call\n")); |
---|
573 | debugp((stderr, "status fd is %d\n", fdstatus)); |
---|
574 | |
---|
575 | memset(&self, 0, sizeof(self)); |
---|
576 | self.sin_addr.s_addr = htonl(INADDR_ANY); |
---|
577 | self.sin_family = AF_INET; |
---|
578 | self.sin_port = htons(9101); |
---|
579 | |
---|
580 | if (bind(fdstatus, (struct sockaddr *)&self, sizeof(self)) < 0) { |
---|
581 | fprintf(stderr, "%s: bind of local address failed (status)\n", prog); |
---|
582 | cleanupandexit(2); |
---|
583 | } |
---|
584 | |
---|
585 | if ((fdcontrol = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
---|
586 | fprintf(stderr, "%s: error creating control socket\n", prog); |
---|
587 | cleanupandexit(2); |
---|
588 | } |
---|
589 | |
---|
590 | if (setsockopt(fdcontrol, IPPROTO_TCP, TCP_NODELAY, (char *)&foo, |
---|
591 | sizeof(foo)) < 0) { |
---|
592 | perror("sockcomm: setsockopt (no delay)"); |
---|
593 | cleanupandexit(2); |
---|
594 | } |
---|
595 | memset(&self, 0, sizeof(self)); |
---|
596 | self.sin_addr.s_addr = htonl(INADDR_ANY); |
---|
597 | self.sin_family = AF_INET; |
---|
598 | self.sin_port = htons(0); |
---|
599 | if (bind(fdcontrol, (struct sockaddr *)&self, sizeof(self)) < 0) { |
---|
600 | fprintf(stderr, "%s: bind of local address failed (control)\n", prog); |
---|
601 | cleanupandexit(2); |
---|
602 | } |
---|
603 | socklen = sizeof(statussock); |
---|
604 | if (control && status) { |
---|
605 | if (connect(fdcontrol, (struct sockaddr *)&statussock, socklen) < 0 ) { |
---|
606 | fprintf(stderr, "error connecting\n"); |
---|
607 | perror(""); |
---|
608 | cleanupandexit(1); |
---|
609 | } |
---|
610 | debugp((stderr, "after connect call (control)\n")); |
---|
611 | } |
---|
612 | |
---|
613 | currentstate = syncstart; |
---|
614 | |
---|
615 | if ((fdsend = socket(AF_INET, SOCK_STREAM, 0)) < 0) { |
---|
616 | fprintf(stderr, "%s: error creating data socket\n", prog); |
---|
617 | cleanupandexit(2); |
---|
618 | } |
---|
619 | debugp((stderr, "after data socket call\n")); |
---|
620 | debugp((stderr, "TCP file descriptor (data) %d\n", fdsend)); |
---|
621 | |
---|
622 | memset(&self, 0, sizeof(self)); |
---|
623 | self.sin_addr.s_addr = htonl(INADDR_ANY); |
---|
624 | self.sin_family = AF_INET; |
---|
625 | /* let system pick it, then we'll tell printer */ |
---|
626 | self.sin_port = htons(0); |
---|
627 | if (bind(fdsend, (struct sockaddr *)&self, sizeof(self)) < 0) { |
---|
628 | fprintf(stderr, "%s: bind of local address failed (data)\n", prog); |
---|
629 | cleanupandexit(2); |
---|
630 | } |
---|
631 | |
---|
632 | getsockname(fdsend, (struct sockaddr *)&sockname, &namelen); |
---|
633 | localport = sockname.sin_port; |
---|
634 | debugp((stderr, "local port is %d\n", ntohs(localport))); |
---|
635 | memset(&controldata, 0, sizeof(controldata)); |
---|
636 | controldata.ctrlchar = 0x01; |
---|
637 | JobControl(controldata); |
---|
638 | |
---|
639 | controldata.ctrlchar = 0x02; |
---|
640 | controldata.port = localport; |
---|
641 | JobControl(controldata); |
---|
642 | |
---|
643 | debugp((stderr, "trying to connect to data socket...\n")); |
---|
644 | |
---|
645 | socklen = sizeof(datasock); |
---|
646 | if (connect(fdsend, (struct sockaddr *)&datasock, socklen) < 0 ) { |
---|
647 | fprintf(stderr, "%s: error connecting (data)\n", prog); |
---|
648 | perror(""); |
---|
649 | cleanupandexit(2); |
---|
650 | } |
---|
651 | debugp((stderr, "after connect call \n")); |
---|
652 | |
---|
653 | /* do accounting, if necessary */ |
---|
654 | |
---|
655 | if (doactng) { |
---|
656 | AccountingJob(&startpagecount); |
---|
657 | ReopenConn(); |
---|
658 | } |
---|
659 | |
---|
660 | /* fork a child for listening */ |
---|
661 | if ((pid = fork()) < 0) { |
---|
662 | fprintf(stderr, "fork failed \n"); |
---|
663 | perror(""); |
---|
664 | cleanupandexit(2); |
---|
665 | } |
---|
666 | if (pid == 0) { |
---|
667 | currentstate = child; |
---|
668 | Listener(); |
---|
669 | /* should never get here */ |
---|
670 | exit(2); |
---|
671 | } |
---|
672 | /* parent */ |
---|
673 | |
---|
674 | /* send file */ |
---|
675 | currentstate = sending; |
---|
676 | if (bannerfirst) { |
---|
677 | SendBanner(0); |
---|
678 | if (!bannerlast) unlink(".banner"); |
---|
679 | } |
---|
680 | debugp((stderr, "sending file\n")); |
---|
681 | while ((cnt = read(fdinput, mybuf, sizeof(mybuf))) > 0) { |
---|
682 | mbp = mybuf; |
---|
683 | debugp((stderr, "parent: read %d bytes\n", cnt)); |
---|
684 | while ((cnt > 0) && ((wc = write(fdsend, mbp, cnt)) != cnt)) { |
---|
685 | if (wc < 0) { |
---|
686 | fprintf(stderr, "%s: error writing to printer\n", prog); |
---|
687 | perror(""); |
---|
688 | sleep(10); |
---|
689 | kill(pid, SIGEMT); |
---|
690 | cleanupandexit(1); |
---|
691 | } |
---|
692 | debugp((stderr, "parent: wrote %d bytes\n", wc)); |
---|
693 | mbp += wc; |
---|
694 | cnt -= wc; |
---|
695 | } |
---|
696 | debugp((stderr, "parent: wrote it all, read some more\n")); |
---|
697 | } |
---|
698 | linger.l_onoff = 0; |
---|
699 | linger.l_linger = 0; |
---|
700 | if (setsockopt(fdsend, SOL_SOCKET, SO_LINGER, (char *)&linger, |
---|
701 | sizeof(linger)) |
---|
702 | < 0) { |
---|
703 | perror("sockcomm: setsockopt(linger)"); |
---|
704 | cleanupandexit(2); |
---|
705 | } |
---|
706 | close(fdinput); |
---|
707 | shutdown(fdsend, 1); |
---|
708 | debugp((stderr, "after shutdown\n")); |
---|
709 | if (cnt < 0) { |
---|
710 | fprintf(stderr, "%s: error reading input file\n", prog); |
---|
711 | perror(""); |
---|
712 | sleep(10); |
---|
713 | kill(pid, SIGEMT); |
---|
714 | cleanupandexit(1); |
---|
715 | } |
---|
716 | debugp((stderr, "sent file\n")); |
---|
717 | currentstate = waiting; |
---|
718 | while ((childpid=wait(&statusp)) > 0) { |
---|
719 | debugp((stderr, "parent: wait returned pid %d status %d\n", |
---|
720 | childpid, statusp)); |
---|
721 | if (childpid == pid) |
---|
722 | break; |
---|
723 | } |
---|
724 | if (bannerlast) { |
---|
725 | currentstate = lastpart; |
---|
726 | ReopenConn(); |
---|
727 | SendBanner(1); |
---|
728 | close(fdsend); |
---|
729 | if (bannerlast > 1) unlink(".banner"); |
---|
730 | } |
---|
731 | if (doactng) { |
---|
732 | currentstate = synclast; |
---|
733 | ReopenConn(); |
---|
734 | AccountingJob(&endpagecount); |
---|
735 | AcctEntry(startpagecount, endpagecount); |
---|
736 | } |
---|
737 | currentstate = ending; |
---|
738 | controldata.ctrlchar = 0x04; |
---|
739 | controldata.port = htons(0); |
---|
740 | JobControl(controldata); |
---|
741 | } |
---|
742 | |
---|
743 | |
---|
744 | #define ARGS "P:n:h:p:" |
---|
745 | extern char *optarg; |
---|
746 | extern int optind; |
---|
747 | |
---|
748 | main(argc, argv) |
---|
749 | int argc; |
---|
750 | char **argv; |
---|
751 | { |
---|
752 | int i; |
---|
753 | int argp; |
---|
754 | long starttime; |
---|
755 | char *tmp; |
---|
756 | long addr; |
---|
757 | |
---|
758 | |
---|
759 | currentstate = init; |
---|
760 | while ((argp = getopt(argc, argv, ARGS)) != EOF) { |
---|
761 | switch(argp) { |
---|
762 | case 'P': |
---|
763 | /* printer name */ |
---|
764 | pname = optarg; |
---|
765 | break; |
---|
766 | case 'n': |
---|
767 | name = optarg; |
---|
768 | break; |
---|
769 | case 'h': |
---|
770 | host = optarg; |
---|
771 | break; |
---|
772 | case 'p': |
---|
773 | prog = optarg; |
---|
774 | break; |
---|
775 | } |
---|
776 | } |
---|
777 | |
---|
778 | if (argc > optind) |
---|
779 | accountingfile = argv[optind]; |
---|
780 | |
---|
781 | doactng = name && accountingfile && (access(accountingfile, W_OK) == 0); |
---|
782 | |
---|
783 | if (tmp = getenv("BANNERFIRST")) |
---|
784 | bannerfirst = atoi(tmp); |
---|
785 | |
---|
786 | if (tmp = getenv("BANNERLAST")) |
---|
787 | bannerlast = atoi(tmp); |
---|
788 | |
---|
789 | if (tmp = getenv("ASCONTROL")) |
---|
790 | control = atoi(tmp); |
---|
791 | |
---|
792 | if (tmp = getenv("ASSTATUS")) |
---|
793 | status = atoi(tmp); |
---|
794 | |
---|
795 | /* init signal processing */ |
---|
796 | #ifdef BDEBUG |
---|
797 | for (i=1; i<31; i++) |
---|
798 | if (i != SIGCHLD) |
---|
799 | signal(i, handler); |
---|
800 | #endif |
---|
801 | signal(SIGEMT, giveup); |
---|
802 | signal(SIGINT, abortjob); |
---|
803 | signal(SIGHUP, abortjob); |
---|
804 | signal(SIGTERM, abortjob); |
---|
805 | #ifdef SYSV |
---|
806 | sigignore(SIGPIPE); |
---|
807 | #endif /* SYSV */ |
---|
808 | |
---|
809 | #ifdef BSD |
---|
810 | time(&starttime); |
---|
811 | fprintf(stderr, "%s: %s:%s %s start - %s", prog, host, name, pname, |
---|
812 | ctime(&starttime)); |
---|
813 | fflush(stderr); |
---|
814 | #endif /* BSD */ |
---|
815 | |
---|
816 | ppid = getpid(); |
---|
817 | |
---|
818 | fdinput = fileno(stdin); |
---|
819 | |
---|
820 | memset(&statussock, 0, sizeof(statussock)); |
---|
821 | memset(&datasock, 0, sizeof(datasock)); |
---|
822 | datasock.sin_addr.s_addr = inet_addr(pname); |
---|
823 | statussock.sin_addr.s_addr = inet_addr(pname); |
---|
824 | if (datasock.sin_addr.s_addr == -1) { |
---|
825 | if ((hp = gethostbyname(pname)) == NULL) { |
---|
826 | fprintf(stderr, "%s: couldn't find host %s.\n", prog, pname); |
---|
827 | cleanupandexit(2); |
---|
828 | } |
---|
829 | debugp((stderr, "after gethostbyname\n")); |
---|
830 | debugp((stderr, |
---|
831 | "printer hostent fields: name %s\n addr %s length 0x%x\n", |
---|
832 | hp->h_name, inet_ntoa((struct in_addr *) (hp->h_addr)), |
---|
833 | hp->h_length)); |
---|
834 | memcpy(&datasock.sin_addr, hp->h_addr, hp->h_length); |
---|
835 | memcpy(&statussock.sin_addr, hp->h_addr, hp->h_length); |
---|
836 | } |
---|
837 | |
---|
838 | debugp((stderr, "port no. %d\n", dataport)); |
---|
839 | |
---|
840 | datasock.sin_family = AF_INET; |
---|
841 | datasock.sin_port = htons(dataport); |
---|
842 | |
---|
843 | statussock.sin_family = AF_INET; |
---|
844 | statussock.sin_port = htons(statusport); |
---|
845 | |
---|
846 | debugp((stderr, "status port no %d\n", statusport)); |
---|
847 | |
---|
848 | SendFile(); |
---|
849 | |
---|
850 | #ifdef BSD |
---|
851 | time(&starttime); |
---|
852 | fprintf(stderr, "%s: end - %s", prog, ctime(&starttime)); |
---|
853 | fflush(stderr); |
---|
854 | #endif /* BSD */ |
---|
855 | cleanupandexit(0); |
---|
856 | } |
---|