1 #ifdef plan9
2
3 #include <u.h>
4 #include <libc.h>
5
6 enum {
7 stderr = 2,
8 RDNETIMEOUT = 30*60*1000,
9 WRNETIMEOUT = RDNETIMEOUT,
10 };
11 #else
12
13 /* not for plan 9 */
14 #include <stdio.h>
15 #include <errno.h>
16 #include <time.h>
17 #include <fcntl.h>
18 #include <signal.h>
19
20 #define create creat
21 #define seek lseek
22 #define fprint fprintf
23 #define sprint sprintf
24 #define exits exit
25
26 #define ORDWR O_RDWR
27 #define OTRUNC O_TRUNC
28 #define ORCLOSE 0
29
30 #define RDNETIMEOUT 60
31 #define WRNETIMEOUT 60
32
33 #endif
34
35 #define MIN(a,b) ((a<b)?a:b)
36
37 #define ACK(a) write(a, "", 1)
38 #define NAK(a) write(a, "\001", 1)
39
40 #define LPDAEMONLOG "/tmp/lpdaemonl"
41
42 #define LNBFSZ 4096
43 char lnbuf[LNBFSZ];
44 int dbgstate = 0;
45 char *dbgstrings[] = {
46 "",
47 "rcvack1",
48 "send",
49 "rcvack2",
50 "response",
51 "done"
52 };
53
54 #ifdef plan9
55
56 void
error(int level,char * s1,...)57 error(int level, char *s1, ...)
58 {
59 va_list ap;
60 long thetime;
61 char *chartime;
62 char *args[8];
63 int argno = 0;
64
65 if (level == 0) {
66 time(&thetime);
67 chartime = ctime(thetime);
68 fprint(stderr, "%.15s ", &(chartime[4]));
69 }
70 va_start(ap, s1);
71 while(args[argno++] = va_arg(ap, char*))
72 ;
73 va_end(ap);
74 fprint(stderr, s1, *args);
75 }
76
77 int
alarmhandler(void * foo,char * note)78 alarmhandler(void *foo, char *note) {
79 USED(foo);
80 if(strcmp(note, "alarm")==0) {
81 fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
82 return(1);
83 } else return(0);
84 }
85
86 #else
87
88 void
error(int level,char * s1,...)89 error(int level, char *s1, ...)
90 {
91 time_t thetime;
92 char *chartime;
93
94 if (level == 0) {
95 time(&thetime);
96 chartime = ctime(&thetime);
97 fprintf(stderr, "%.15s ", &(chartime[4]));
98 }
99 fprintf(stderr, s1, &s1 + 1);
100 }
101
102 void
alarmhandler()103 alarmhandler() {
104 fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
105 }
106
107 #endif
108
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
readline(int inpfd)114 readline(int inpfd)
115 {
116 register char *ap;
117 register int i;
118
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;
125 }
126 } while ((++i < LNBFSZ - 2) && *ap++ != '\n');
127 if (i == LNBFSZ - 2) {
128 *ap = '\n';
129 i++;
130 }
131 *ap = '\0';
132 return(i);
133 }
134
135 #define RDSIZE 512
136 char jobbuf[RDSIZE];
137
138 int
pass(int inpfd,int outfd,int bsize)139 pass(int inpfd, int outfd, int bsize)
140 {
141 int rv, bcnt;
142
143 for(bcnt=bsize; bcnt > 0; bcnt -= rv) {
144 alarm(WRNETIMEOUT); /* to break hanging */
145 if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
146 error(0, "read error during pass, %d remaining\n", bcnt);
147 break;
148 } else if((write(outfd, jobbuf, rv)) != rv) {
149 error(0, "write error during pass, %d remaining\n", bcnt);
150 break;
151 }
152 }
153 alarm(0);
154 return(bcnt);
155 }
156
157 /* get whatever stdin has and put it into the temporary file.
158 * return the file size.
159 */
160 int
prereadfile(int inpfd)161 prereadfile(int inpfd)
162 {
163 int rv, bsize;
164
165 bsize = 0;
166 do {
167 if((rv=read(0, jobbuf, RDSIZE))<0) {
168 error(0, "read error while making temp file\n");
169 exits("read error while making temp file");
170 } else if((write(inpfd, jobbuf, rv)) != rv) {
171 error(0, "write error while making temp file\n");
172 exits("write error while making temp file");
173 }
174 bsize += rv;
175 } while (rv!=0);
176 return(bsize);
177 }
178
179 int
tempfile(void)180 tempfile(void)
181 {
182 static tindx = 0;
183 char tmpf[20];
184 int tmpfd;
185
186 sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);
187 if((tmpfd=create(tmpf,
188 #ifdef plan9
189 ORDWR|OTRUNC,
190 #endif
191 0666)) < 0) {
192 error(0, "cannot create temp file %s\n", tmpf);
193 exits("cannot create temp file");
194 }
195 close(tmpfd);
196 if((tmpfd=open(tmpf, ORDWR
197 #ifdef plan9
198 |ORCLOSE|OTRUNC
199 #endif
200 )) < 0) {
201 error(0, "cannot open temp file %s\n", tmpf);
202 exits("cannot open temp file");
203 }
204 return(tmpfd);
205 }
206
207 int
recvACK(int netfd)208 recvACK(int netfd)
209 {
210 int rv;
211
212 *jobbuf = '\0';
213 alarm(RDNETIMEOUT);
214 if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
215 error(0, "failed to receive ACK, ");
216 if (*jobbuf == '\0')
217 error(1, "read failed\n");
218 else
219 error(1, "received <%#x> instead\n", (uchar)*jobbuf);
220 rv = 0;
221 } else rv = 1;
222 alarm(0);
223 return(rv);
224 }
225
226 void
main(int argc,char * argv[])227 main(int argc, char *argv[])
228 {
229 int i, rv, netfd, bsize, datafd;
230 #ifndef plan9
231 void (*oldhandler)();
232 #endif
233
234 /* make connection */
235 if (argc != 2) {
236 fprint(stderr, "usage: %s network!destination!service\n",
237 argv[0]);
238 exits("usage");
239 }
240
241 /* read options line from stdin into lnbuf */
242 i = readline(0);
243
244 /* read stdin into tempfile to get size */
245 datafd = tempfile();
246 bsize = prereadfile(datafd);
247
248 /* network connection is opened after data is in to avoid timeout */
249 if ((netfd = dial(argv[1], 0, 0, 0)) < 0) {
250 fprint(stderr, "dialing ");
251 perror(argv[1]);
252 exits("can't dial");
253 }
254
255 /* write out the options we read above */
256 if (write(netfd, lnbuf, i) != i) {
257 error(0, "write error while sending options\n");
258 exits("write error sending options");
259 }
260
261 /* send the size of the file to be sent */
262 sprint(lnbuf, "%d\n", bsize);
263 i = strlen(lnbuf);
264 if ((rv=write(netfd, lnbuf, i)) != i) {
265 perror("write error while sending size");
266 error(0, "write returned %d\n", rv);
267 exits("write error sending size");
268 }
269
270 if (seek(datafd, 0L, 0) < 0) {
271 error(0, "error seeking temp file\n");
272 exits("seek error");
273 }
274 /* mirror performance in readfile() in lpdaemon */
275
276 #ifdef plan9
277 atnotify(alarmhandler, 1);
278 #else
279 oldhandler = signal(SIGALRM, alarmhandler);
280 #endif
281
282 dbgstate = 1;
283 if(!recvACK(netfd)) {
284 error(0, "failed to receive ACK before sending data\n");
285 exits("recv ack1 failed");
286 }
287 dbgstate = 2;
288 if ((i=pass(datafd, netfd, bsize)) != 0) {
289 NAK(netfd);
290 error(0, "failed to send %d bytes\n", i);
291 exits("send data failed");
292 }
293 ACK(netfd);
294 dbgstate = 3;
295 if(!recvACK(netfd)) {
296 error(0, "failed to receive ACK after sending data\n");
297 exits("recv ack2 failed");
298 }
299
300 /* get response, as from lp -q */
301 dbgstate = 4;
302 while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
303 if((write(1, jobbuf, rv)) != rv) {
304 error(0, "write error while sending to stdout\n");
305 exits("write error while sending to stdout");
306 }
307 }
308 dbgstate = 5;
309
310 #ifdef plan9
311 atnotify(alarmhandler, 0);
312 /* close down network connections and go away */
313 exits("");
314 #else
315 signal(SIGALRM, oldhandler);
316 exit(0);
317 #endif
318 }
319