17dd7cddfSDavid du Colombier #ifdef plan9
27dd7cddfSDavid du Colombier
3bd389b36SDavid du Colombier #include <u.h>
4bd389b36SDavid du Colombier #include <libc.h>
57dd7cddfSDavid du Colombier
67ec5746aSDavid du Colombier enum {
77ec5746aSDavid du Colombier stderr = 2,
87ec5746aSDavid du Colombier RDNETIMEOUT = 30*60*1000,
97ec5746aSDavid du Colombier WRNETIMEOUT = RDNETIMEOUT,
107ec5746aSDavid du Colombier };
117dd7cddfSDavid du Colombier #else
12bd389b36SDavid du Colombier
13bd389b36SDavid du Colombier /* not for plan 9 */
147dd7cddfSDavid du Colombier #include <stdio.h>
157dd7cddfSDavid du Colombier #include <errno.h>
167dd7cddfSDavid du Colombier #include <time.h>
177dd7cddfSDavid du Colombier #include <fcntl.h>
187dd7cddfSDavid du Colombier #include <signal.h>
197dd7cddfSDavid du Colombier
207dd7cddfSDavid du Colombier #define create creat
217dd7cddfSDavid du Colombier #define seek lseek
227dd7cddfSDavid du Colombier #define fprint fprintf
237dd7cddfSDavid du Colombier #define sprint sprintf
247dd7cddfSDavid du Colombier #define exits exit
257dd7cddfSDavid du Colombier
267dd7cddfSDavid du Colombier #define ORDWR O_RDWR
277dd7cddfSDavid du Colombier #define OTRUNC O_TRUNC
287dd7cddfSDavid du Colombier #define ORCLOSE 0
297dd7cddfSDavid du Colombier
307dd7cddfSDavid du Colombier #define RDNETIMEOUT 60
317dd7cddfSDavid du Colombier #define WRNETIMEOUT 60
327dd7cddfSDavid du Colombier
337dd7cddfSDavid du Colombier #endif
34bd389b36SDavid du Colombier
35bd389b36SDavid du Colombier #define MIN(a,b) ((a<b)?a:b)
36bd389b36SDavid du Colombier
37bd389b36SDavid du Colombier #define ACK(a) write(a, "", 1)
38bd389b36SDavid du Colombier #define NAK(a) write(a, "\001", 1)
39bd389b36SDavid du Colombier
40bd389b36SDavid du Colombier #define LPDAEMONLOG "/tmp/lpdaemonl"
41bd389b36SDavid du Colombier
42bd389b36SDavid du Colombier #define LNBFSZ 4096
43bd389b36SDavid du Colombier char lnbuf[LNBFSZ];
44bd389b36SDavid du Colombier int dbgstate = 0;
45bd389b36SDavid du Colombier char *dbgstrings[] = {
46bd389b36SDavid du Colombier "",
47bd389b36SDavid du Colombier "rcvack1",
48bd389b36SDavid du Colombier "send",
49bd389b36SDavid du Colombier "rcvack2",
50bd389b36SDavid du Colombier "response",
51bd389b36SDavid du Colombier "done"
52bd389b36SDavid du Colombier };
537dd7cddfSDavid du Colombier
547dd7cddfSDavid du Colombier #ifdef plan9
557dd7cddfSDavid du Colombier
56bd389b36SDavid du Colombier void
error(int level,char * s1,...)57bd389b36SDavid du Colombier error(int level, char *s1, ...)
58bd389b36SDavid du Colombier {
597dd7cddfSDavid du Colombier va_list ap;
60bd389b36SDavid du Colombier long thetime;
61bd389b36SDavid du Colombier char *chartime;
62bd389b36SDavid du Colombier char *args[8];
63bd389b36SDavid du Colombier int argno = 0;
64bd389b36SDavid du Colombier
65bd389b36SDavid du Colombier if (level == 0) {
66bd389b36SDavid du Colombier time(&thetime);
67bd389b36SDavid du Colombier chartime = ctime(thetime);
687dd7cddfSDavid du Colombier fprint(stderr, "%.15s ", &(chartime[4]));
69bd389b36SDavid du Colombier }
70bd389b36SDavid du Colombier va_start(ap, s1);
7143af371bSDavid du Colombier while(args[argno++] = va_arg(ap, char*))
7243af371bSDavid du Colombier ;
73bd389b36SDavid du Colombier va_end(ap);
747dd7cddfSDavid du Colombier fprint(stderr, s1, *args);
75bd389b36SDavid du Colombier }
76bd389b36SDavid du Colombier
77bd389b36SDavid du Colombier int
alarmhandler(void * foo,char * note)78bd389b36SDavid du Colombier alarmhandler(void *foo, char *note) {
79bd389b36SDavid du Colombier USED(foo);
809a747e4fSDavid du Colombier if(strcmp(note, "alarm")==0) {
817dd7cddfSDavid du Colombier fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
82bd389b36SDavid du Colombier return(1);
83bd389b36SDavid du Colombier } else return(0);
84bd389b36SDavid du Colombier }
85bd389b36SDavid du Colombier
867dd7cddfSDavid du Colombier #else
877dd7cddfSDavid du Colombier
887dd7cddfSDavid du Colombier void
error(int level,char * s1,...)897dd7cddfSDavid du Colombier error(int level, char *s1, ...)
907dd7cddfSDavid du Colombier {
917dd7cddfSDavid du Colombier time_t thetime;
927dd7cddfSDavid du Colombier char *chartime;
937dd7cddfSDavid du Colombier
947dd7cddfSDavid du Colombier if (level == 0) {
957dd7cddfSDavid du Colombier time(&thetime);
967dd7cddfSDavid du Colombier chartime = ctime(&thetime);
977dd7cddfSDavid du Colombier fprintf(stderr, "%.15s ", &(chartime[4]));
987dd7cddfSDavid du Colombier }
9943af371bSDavid du Colombier fprintf(stderr, s1, &s1 + 1);
1007dd7cddfSDavid du Colombier }
1017dd7cddfSDavid du Colombier
1027dd7cddfSDavid du Colombier void
alarmhandler()1037dd7cddfSDavid du Colombier alarmhandler() {
1047dd7cddfSDavid du Colombier fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);
1057dd7cddfSDavid du Colombier }
1067dd7cddfSDavid du Colombier
1077dd7cddfSDavid du Colombier #endif
1087dd7cddfSDavid du Colombier
109bd389b36SDavid du Colombier /* get a line from inpfd using nonbuffered input. The line is truncated if it is too
110bd389b36SDavid du Colombier * long for the buffer. The result is left in lnbuf and the number of characters
111bd389b36SDavid du Colombier * read in is returned.
112bd389b36SDavid du Colombier */
113bd389b36SDavid du Colombier int
readline(int inpfd)114bd389b36SDavid du Colombier readline(int inpfd)
115bd389b36SDavid du Colombier {
116bd389b36SDavid du Colombier register char *ap;
117bd389b36SDavid du Colombier register int i;
118bd389b36SDavid du Colombier
119bd389b36SDavid du Colombier ap = lnbuf;
120bd389b36SDavid du Colombier i = 0;
121bd389b36SDavid du Colombier do {
122bd389b36SDavid du Colombier if (read(inpfd, ap, 1) != 1) {
123bd389b36SDavid du Colombier error(0, "read error in readline, fd=%d\n", inpfd);
124bd389b36SDavid du Colombier break;
125bd389b36SDavid du Colombier }
126bd389b36SDavid du Colombier } while ((++i < LNBFSZ - 2) && *ap++ != '\n');
127bd389b36SDavid du Colombier if (i == LNBFSZ - 2) {
128bd389b36SDavid du Colombier *ap = '\n';
129bd389b36SDavid du Colombier i++;
130bd389b36SDavid du Colombier }
131bd389b36SDavid du Colombier *ap = '\0';
132bd389b36SDavid du Colombier return(i);
133bd389b36SDavid du Colombier }
134bd389b36SDavid du Colombier
135bd389b36SDavid du Colombier #define RDSIZE 512
136bd389b36SDavid du Colombier char jobbuf[RDSIZE];
137bd389b36SDavid du Colombier
138bd389b36SDavid du Colombier int
pass(int inpfd,int outfd,int bsize)139bd389b36SDavid du Colombier pass(int inpfd, int outfd, int bsize)
140bd389b36SDavid du Colombier {
141*14f51593SDavid du Colombier int rv, bcnt;
142bd389b36SDavid du Colombier
143bd389b36SDavid du Colombier for(bcnt=bsize; bcnt > 0; bcnt -= rv) {
144bd389b36SDavid du Colombier alarm(WRNETIMEOUT); /* to break hanging */
145bd389b36SDavid du Colombier if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {
146bd389b36SDavid du Colombier error(0, "read error during pass, %d remaining\n", bcnt);
147bd389b36SDavid du Colombier break;
148bd389b36SDavid du Colombier } else if((write(outfd, jobbuf, rv)) != rv) {
149bd389b36SDavid du Colombier error(0, "write error during pass, %d remaining\n", bcnt);
150bd389b36SDavid du Colombier break;
151bd389b36SDavid du Colombier }
152bd389b36SDavid du Colombier }
153bd389b36SDavid du Colombier alarm(0);
154bd389b36SDavid du Colombier return(bcnt);
155bd389b36SDavid du Colombier }
156bd389b36SDavid du Colombier
157bd389b36SDavid du Colombier /* get whatever stdin has and put it into the temporary file.
158bd389b36SDavid du Colombier * return the file size.
159bd389b36SDavid du Colombier */
160bd389b36SDavid du Colombier int
prereadfile(int inpfd)161bd389b36SDavid du Colombier prereadfile(int inpfd)
162bd389b36SDavid du Colombier {
163bd389b36SDavid du Colombier int rv, bsize;
164bd389b36SDavid du Colombier
165bd389b36SDavid du Colombier bsize = 0;
166bd389b36SDavid du Colombier do {
167bd389b36SDavid du Colombier if((rv=read(0, jobbuf, RDSIZE))<0) {
168bd389b36SDavid du Colombier error(0, "read error while making temp file\n");
169bd389b36SDavid du Colombier exits("read error while making temp file");
170bd389b36SDavid du Colombier } else if((write(inpfd, jobbuf, rv)) != rv) {
171bd389b36SDavid du Colombier error(0, "write error while making temp file\n");
172bd389b36SDavid du Colombier exits("write error while making temp file");
173bd389b36SDavid du Colombier }
174bd389b36SDavid du Colombier bsize += rv;
175bd389b36SDavid du Colombier } while (rv!=0);
176bd389b36SDavid du Colombier return(bsize);
177bd389b36SDavid du Colombier }
178bd389b36SDavid du Colombier
179bd389b36SDavid du Colombier int
tempfile(void)1807dd7cddfSDavid du Colombier tempfile(void)
181bd389b36SDavid du Colombier {
182bd389b36SDavid du Colombier static tindx = 0;
183bd389b36SDavid du Colombier char tmpf[20];
184bd389b36SDavid du Colombier int tmpfd;
185bd389b36SDavid du Colombier
186bd389b36SDavid du Colombier sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);
1877dd7cddfSDavid du Colombier if((tmpfd=create(tmpf,
1887dd7cddfSDavid du Colombier #ifdef plan9
1897dd7cddfSDavid du Colombier ORDWR|OTRUNC,
1907dd7cddfSDavid du Colombier #endif
1917dd7cddfSDavid du Colombier 0666)) < 0) {
192bd389b36SDavid du Colombier error(0, "cannot create temp file %s\n", tmpf);
193bd389b36SDavid du Colombier exits("cannot create temp file");
194bd389b36SDavid du Colombier }
1957dd7cddfSDavid du Colombier close(tmpfd);
1967dd7cddfSDavid du Colombier if((tmpfd=open(tmpf, ORDWR
1977dd7cddfSDavid du Colombier #ifdef plan9
1987dd7cddfSDavid du Colombier |ORCLOSE|OTRUNC
1997dd7cddfSDavid du Colombier #endif
2007dd7cddfSDavid du Colombier )) < 0) {
2017dd7cddfSDavid du Colombier error(0, "cannot open temp file %s\n", tmpf);
2027dd7cddfSDavid du Colombier exits("cannot open temp file");
2037dd7cddfSDavid du Colombier }
204bd389b36SDavid du Colombier return(tmpfd);
205bd389b36SDavid du Colombier }
206bd389b36SDavid du Colombier
207bd389b36SDavid du Colombier int
recvACK(int netfd)208bd389b36SDavid du Colombier recvACK(int netfd)
209bd389b36SDavid du Colombier {
210bd389b36SDavid du Colombier int rv;
211bd389b36SDavid du Colombier
212bd389b36SDavid du Colombier *jobbuf = '\0';
213bd389b36SDavid du Colombier alarm(RDNETIMEOUT);
214bd389b36SDavid du Colombier if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
215bd389b36SDavid du Colombier error(0, "failed to receive ACK, ");
216bd389b36SDavid du Colombier if (*jobbuf == '\0')
217bd389b36SDavid du Colombier error(1, "read failed\n");
218bd389b36SDavid du Colombier else
2195da35e22SDavid du Colombier error(1, "received <%#x> instead\n", (uchar)*jobbuf);
220bd389b36SDavid du Colombier rv = 0;
221bd389b36SDavid du Colombier } else rv = 1;
222bd389b36SDavid du Colombier alarm(0);
223bd389b36SDavid du Colombier return(rv);
224bd389b36SDavid du Colombier }
225bd389b36SDavid du Colombier
226bd389b36SDavid du Colombier void
main(int argc,char * argv[])227bd389b36SDavid du Colombier main(int argc, char *argv[])
228bd389b36SDavid du Colombier {
2293b86f2f8SDavid du Colombier int i, rv, netfd, bsize, datafd;
2307dd7cddfSDavid du Colombier #ifndef plan9
2317dd7cddfSDavid du Colombier void (*oldhandler)();
2327dd7cddfSDavid du Colombier #endif
233bd389b36SDavid du Colombier
234bd389b36SDavid du Colombier /* make connection */
2357dd7cddfSDavid du Colombier if (argc != 2) {
2363b86f2f8SDavid du Colombier fprint(stderr, "usage: %s network!destination!service\n",
2373b86f2f8SDavid du Colombier argv[0]);
2383b86f2f8SDavid du Colombier exits("usage");
239bd389b36SDavid du Colombier }
2407dd7cddfSDavid du Colombier
2417dd7cddfSDavid du Colombier /* read options line from stdin into lnbuf */
2427dd7cddfSDavid du Colombier i = readline(0);
2437dd7cddfSDavid du Colombier
2447dd7cddfSDavid du Colombier /* read stdin into tempfile to get size */
2457dd7cddfSDavid du Colombier datafd = tempfile();
2467dd7cddfSDavid du Colombier bsize = prereadfile(datafd);
2477dd7cddfSDavid du Colombier
2487dd7cddfSDavid du Colombier /* network connection is opened after data is in to avoid timeout */
2497dd7cddfSDavid du Colombier if ((netfd = dial(argv[1], 0, 0, 0)) < 0) {
2503b86f2f8SDavid du Colombier fprint(stderr, "dialing ");
2513b86f2f8SDavid du Colombier perror(argv[1]);
252bd389b36SDavid du Colombier exits("can't dial");
253bd389b36SDavid du Colombier }
254bd389b36SDavid du Colombier
2557dd7cddfSDavid du Colombier /* write out the options we read above */
256bd389b36SDavid du Colombier if (write(netfd, lnbuf, i) != i) {
257bd389b36SDavid du Colombier error(0, "write error while sending options\n");
2583b86f2f8SDavid du Colombier exits("write error sending options");
259bd389b36SDavid du Colombier }
260bd389b36SDavid du Colombier
261bd389b36SDavid du Colombier /* send the size of the file to be sent */
2627dd7cddfSDavid du Colombier sprint(lnbuf, "%d\n", bsize);
2637dd7cddfSDavid du Colombier i = strlen(lnbuf);
264219b2ee8SDavid du Colombier if ((rv=write(netfd, lnbuf, i)) != i) {
265219b2ee8SDavid du Colombier perror("write error while sending size");
266219b2ee8SDavid du Colombier error(0, "write returned %d\n", rv);
2673b86f2f8SDavid du Colombier exits("write error sending size");
268bd389b36SDavid du Colombier }
269bd389b36SDavid du Colombier
270bd389b36SDavid du Colombier if (seek(datafd, 0L, 0) < 0) {
271bd389b36SDavid du Colombier error(0, "error seeking temp file\n");
272bd389b36SDavid du Colombier exits("seek error");
273bd389b36SDavid du Colombier }
274bd389b36SDavid du Colombier /* mirror performance in readfile() in lpdaemon */
2757dd7cddfSDavid du Colombier
2767dd7cddfSDavid du Colombier #ifdef plan9
277bd389b36SDavid du Colombier atnotify(alarmhandler, 1);
2787dd7cddfSDavid du Colombier #else
2797dd7cddfSDavid du Colombier oldhandler = signal(SIGALRM, alarmhandler);
2807dd7cddfSDavid du Colombier #endif
2817dd7cddfSDavid du Colombier
282bd389b36SDavid du Colombier dbgstate = 1;
283bd389b36SDavid du Colombier if(!recvACK(netfd)) {
284bd389b36SDavid du Colombier error(0, "failed to receive ACK before sending data\n");
285bd389b36SDavid du Colombier exits("recv ack1 failed");
286bd389b36SDavid du Colombier }
287bd389b36SDavid du Colombier dbgstate = 2;
288bd389b36SDavid du Colombier if ((i=pass(datafd, netfd, bsize)) != 0) {
289bd389b36SDavid du Colombier NAK(netfd);
290bd389b36SDavid du Colombier error(0, "failed to send %d bytes\n", i);
291bd389b36SDavid du Colombier exits("send data failed");
292bd389b36SDavid du Colombier }
293bd389b36SDavid du Colombier ACK(netfd);
294bd389b36SDavid du Colombier dbgstate = 3;
295bd389b36SDavid du Colombier if(!recvACK(netfd)) {
296bd389b36SDavid du Colombier error(0, "failed to receive ACK after sending data\n");
297bd389b36SDavid du Colombier exits("recv ack2 failed");
298bd389b36SDavid du Colombier }
299bd389b36SDavid du Colombier
300bd389b36SDavid du Colombier /* get response, as from lp -q */
301bd389b36SDavid du Colombier dbgstate = 4;
302bd389b36SDavid du Colombier while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
303bd389b36SDavid du Colombier if((write(1, jobbuf, rv)) != rv) {
304bd389b36SDavid du Colombier error(0, "write error while sending to stdout\n");
305bd389b36SDavid du Colombier exits("write error while sending to stdout");
306bd389b36SDavid du Colombier }
307bd389b36SDavid du Colombier }
308bd389b36SDavid du Colombier dbgstate = 5;
3097dd7cddfSDavid du Colombier
3107dd7cddfSDavid du Colombier #ifdef plan9
311bd389b36SDavid du Colombier atnotify(alarmhandler, 0);
312bd389b36SDavid du Colombier /* close down network connections and go away */
313bd389b36SDavid du Colombier exits("");
3147dd7cddfSDavid du Colombier #else
3157dd7cddfSDavid du Colombier signal(SIGALRM, oldhandler);
3167dd7cddfSDavid du Colombier exit(0);
3177dd7cddfSDavid du Colombier #endif
318bd389b36SDavid du Colombier }
319