1bd389b36SDavid du Colombier /* for plan 9 */ 2bd389b36SDavid du Colombier #include <u.h> 3bd389b36SDavid du Colombier #include <libc.h> 4bd389b36SDavid du Colombier #include <stdarg.h> 5bd389b36SDavid du Colombier 6bd389b36SDavid du Colombier /* not for plan 9 */ 7bd389b36SDavid du Colombier /* #include <errno.h> */ 8bd389b36SDavid du Colombier /* #include <time.h> */ 9bd389b36SDavid du Colombier /* #include <ipc.h> */ 10bd389b36SDavid du Colombier 11bd389b36SDavid du Colombier #define MIN(a,b) ((a<b)?a:b) 12bd389b36SDavid du Colombier 13bd389b36SDavid du Colombier #define ACK(a) write(a, "", 1) 14bd389b36SDavid du Colombier #define NAK(a) write(a, "\001", 1) 15bd389b36SDavid du Colombier 16bd389b36SDavid du Colombier #define RDNETIMEOUT 60000 17bd389b36SDavid du Colombier #define WRNETIMEOUT 60000 18bd389b36SDavid du Colombier #define LPDAEMONLOG "/tmp/lpdaemonl" 19bd389b36SDavid du Colombier 20bd389b36SDavid du Colombier #define LNBFSZ 4096 21bd389b36SDavid du Colombier char lnbuf[LNBFSZ]; 22bd389b36SDavid du Colombier int dbgstate = 0; 23bd389b36SDavid du Colombier char *dbgstrings[] = { 24bd389b36SDavid du Colombier "", 25bd389b36SDavid du Colombier "rcvack1", 26bd389b36SDavid du Colombier "send", 27bd389b36SDavid du Colombier "rcvack2", 28bd389b36SDavid du Colombier "response", 29bd389b36SDavid du Colombier "done" 30bd389b36SDavid du Colombier }; 31bd389b36SDavid du Colombier void 32bd389b36SDavid du Colombier error(int level, char *s1, ...) 33bd389b36SDavid du Colombier { 34bd389b36SDavid du Colombier long thetime; 35bd389b36SDavid du Colombier char *chartime; 36bd389b36SDavid du Colombier va_list ap; 37bd389b36SDavid du Colombier char *args[8]; 38bd389b36SDavid du Colombier int argno = 0; 39bd389b36SDavid du Colombier 40bd389b36SDavid du Colombier if (level == 0) { 41bd389b36SDavid du Colombier time(&thetime); 42bd389b36SDavid du Colombier chartime = ctime(thetime); 43bd389b36SDavid du Colombier fprint(2, "%.15s ", &(chartime[4])); 44bd389b36SDavid du Colombier } 45bd389b36SDavid du Colombier va_start(ap, s1); 46bd389b36SDavid du Colombier while(args[argno++] = va_arg(ap, char*)); 47bd389b36SDavid du Colombier va_end(ap); 48bd389b36SDavid du Colombier fprint(2, s1, *args); 49bd389b36SDavid du Colombier return; 50bd389b36SDavid du Colombier } 51bd389b36SDavid du Colombier 52bd389b36SDavid du Colombier int 53bd389b36SDavid du Colombier alarmhandler(void *foo, char *note) { 54bd389b36SDavid du Colombier USED(foo); 55bd389b36SDavid du Colombier if(strncmp(note, "alarm", ERRLEN)==0) { 56bd389b36SDavid du Colombier fprint(2, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); 57bd389b36SDavid du Colombier return(1); 58bd389b36SDavid du Colombier } else return(0); 59bd389b36SDavid du Colombier } 60bd389b36SDavid du Colombier 61bd389b36SDavid du Colombier /* get a line from inpfd using nonbuffered input. The line is truncated if it is too 62bd389b36SDavid du Colombier * long for the buffer. The result is left in lnbuf and the number of characters 63bd389b36SDavid du Colombier * read in is returned. 64bd389b36SDavid du Colombier */ 65bd389b36SDavid du Colombier int 66bd389b36SDavid du Colombier readline(int inpfd) 67bd389b36SDavid du Colombier { 68bd389b36SDavid du Colombier register char *ap; 69bd389b36SDavid du Colombier register int i; 70bd389b36SDavid du Colombier 71bd389b36SDavid du Colombier ap = lnbuf; 72bd389b36SDavid du Colombier i = 0; 73bd389b36SDavid du Colombier do { 74bd389b36SDavid du Colombier if (read(inpfd, ap, 1) != 1) { 75bd389b36SDavid du Colombier error(0, "read error in readline, fd=%d\n", inpfd); 76bd389b36SDavid du Colombier break; 77bd389b36SDavid du Colombier } 78bd389b36SDavid du Colombier } while ((++i < LNBFSZ - 2) && *ap++ != '\n'); 79bd389b36SDavid du Colombier if (i == LNBFSZ - 2) { 80bd389b36SDavid du Colombier *ap = '\n'; 81bd389b36SDavid du Colombier i++; 82bd389b36SDavid du Colombier } 83bd389b36SDavid du Colombier *ap = '\0'; 84bd389b36SDavid du Colombier return(i); 85bd389b36SDavid du Colombier } 86bd389b36SDavid du Colombier 87bd389b36SDavid du Colombier #define RDSIZE 512 88bd389b36SDavid du Colombier char jobbuf[RDSIZE]; 89bd389b36SDavid du Colombier 90bd389b36SDavid du Colombier int 91bd389b36SDavid du Colombier pass(int inpfd, int outfd, int bsize) 92bd389b36SDavid du Colombier { 93bd389b36SDavid du Colombier int bcnt, rv; 94bd389b36SDavid du Colombier 95bd389b36SDavid du Colombier for(bcnt=bsize; bcnt > 0; bcnt -= rv) { 96bd389b36SDavid du Colombier alarm(WRNETIMEOUT); /* to break hanging */ 97bd389b36SDavid du Colombier if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) { 98bd389b36SDavid du Colombier error(0, "read error during pass, %d remaining\n", bcnt); 99bd389b36SDavid du Colombier break; 100bd389b36SDavid du Colombier } else if((write(outfd, jobbuf, rv)) != rv) { 101bd389b36SDavid du Colombier error(0, "write error during pass, %d remaining\n", bcnt); 102bd389b36SDavid du Colombier break; 103bd389b36SDavid du Colombier } 104bd389b36SDavid du Colombier } 105bd389b36SDavid du Colombier alarm(0); 106bd389b36SDavid du Colombier return(bcnt); 107bd389b36SDavid du Colombier } 108bd389b36SDavid du Colombier 109bd389b36SDavid du Colombier /* get whatever stdin has and put it into the temporary file. 110bd389b36SDavid du Colombier * return the file size. 111bd389b36SDavid du Colombier */ 112bd389b36SDavid du Colombier int 113bd389b36SDavid du Colombier prereadfile(int inpfd) 114bd389b36SDavid du Colombier { 115bd389b36SDavid du Colombier int rv, bsize; 116bd389b36SDavid du Colombier 117bd389b36SDavid du Colombier bsize = 0; 118bd389b36SDavid du Colombier do { 119bd389b36SDavid du Colombier if((rv=read(0, jobbuf, RDSIZE))<0) { 120bd389b36SDavid du Colombier error(0, "read error while making temp file\n"); 121bd389b36SDavid du Colombier exits("read error while making temp file"); 122bd389b36SDavid du Colombier } else if((write(inpfd, jobbuf, rv)) != rv) { 123bd389b36SDavid du Colombier error(0, "write error while making temp file\n"); 124bd389b36SDavid du Colombier exits("write error while making temp file"); 125bd389b36SDavid du Colombier } 126bd389b36SDavid du Colombier bsize += rv; 127bd389b36SDavid du Colombier } while (rv!=0); 128bd389b36SDavid du Colombier return(bsize); 129bd389b36SDavid du Colombier } 130bd389b36SDavid du Colombier 131bd389b36SDavid du Colombier int 132bd389b36SDavid du Colombier tmpfile(void) 133bd389b36SDavid du Colombier { 134bd389b36SDavid du Colombier static tindx = 0; 135bd389b36SDavid du Colombier char tmpf[20]; 136bd389b36SDavid du Colombier int tmpfd; 137bd389b36SDavid du Colombier 138bd389b36SDavid du Colombier sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++); 139bd389b36SDavid du Colombier if((tmpfd=create(tmpf, ORDWR|ORCLOSE|OTRUNC, 0666)) < 0) { 140bd389b36SDavid du Colombier error(0, "cannot create temp file %s\n", tmpf); 141bd389b36SDavid du Colombier exits("cannot create temp file"); 142bd389b36SDavid du Colombier } 143bd389b36SDavid du Colombier return(tmpfd); 144bd389b36SDavid du Colombier } 145bd389b36SDavid du Colombier 146bd389b36SDavid du Colombier int 147bd389b36SDavid du Colombier recvACK(int netfd) 148bd389b36SDavid du Colombier { 149bd389b36SDavid du Colombier int rv; 150bd389b36SDavid du Colombier 151bd389b36SDavid du Colombier *jobbuf = '\0'; 152bd389b36SDavid du Colombier alarm(RDNETIMEOUT); 153bd389b36SDavid du Colombier if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') { 154bd389b36SDavid du Colombier error(0, "failed to receive ACK, "); 155bd389b36SDavid du Colombier if (*jobbuf == '\0') 156bd389b36SDavid du Colombier error(1, "read failed\n"); 157bd389b36SDavid du Colombier else 158bd389b36SDavid du Colombier error(1, "received <0x%x> instead\n", *jobbuf); 159bd389b36SDavid du Colombier rv = 0; 160bd389b36SDavid du Colombier } else rv = 1; 161bd389b36SDavid du Colombier alarm(0); 162bd389b36SDavid du Colombier return(rv); 163bd389b36SDavid du Colombier } 164bd389b36SDavid du Colombier 165bd389b36SDavid du Colombier void 166bd389b36SDavid du Colombier main(int argc, char *argv[]) 167bd389b36SDavid du Colombier { 168bd389b36SDavid du Colombier char *devdir; 169bd389b36SDavid du Colombier int i, rv, netfd, bsize, datafd; 170bd389b36SDavid du Colombier 171bd389b36SDavid du Colombier /* make connection */ 172bd389b36SDavid du Colombier if (argc != 4) { 173bd389b36SDavid du Colombier fprint(2, "usage: %s destination network service\n", argv[0]); 174bd389b36SDavid du Colombier exits("incorrect number of arguments"); 175bd389b36SDavid du Colombier } 176bd389b36SDavid du Colombier if ((netfd=dial((devdir=netmkaddr(argv[1], argv[2], argv[3])), 0, 0, 0)) < 0) { 177bd389b36SDavid du Colombier fprint(2, "dialing %s\n", devdir); 178bd389b36SDavid du Colombier perror("dial"); 179bd389b36SDavid du Colombier exits("can't dial"); 180bd389b36SDavid du Colombier } 181bd389b36SDavid du Colombier 182bd389b36SDavid du Colombier /* read options line from stdin and send it */ 183bd389b36SDavid du Colombier i = readline(0); 184bd389b36SDavid du Colombier if (write(netfd, lnbuf, i) != i) { 185bd389b36SDavid du Colombier error(0, "write error while sending options\n"); 186bd389b36SDavid du Colombier exits("write error while sending options"); 187bd389b36SDavid du Colombier } 188bd389b36SDavid du Colombier 189bd389b36SDavid du Colombier /* read stdin into tmpfile to get size */ 190bd389b36SDavid du Colombier datafd = tmpfile(); 191bd389b36SDavid du Colombier bsize = prereadfile(datafd); 192bd389b36SDavid du Colombier 193bd389b36SDavid du Colombier /* send the size of the file to be sent */ 194bd389b36SDavid du Colombier i = sprint(lnbuf, "%d\n", bsize); 195*219b2ee8SDavid du Colombier if ((rv=write(netfd, lnbuf, i)) != i) { 196*219b2ee8SDavid du Colombier perror("write error while sending size"); 197*219b2ee8SDavid du Colombier error(0, "write returned %d\n", rv); 198bd389b36SDavid du Colombier exits("write error while sending size"); 199bd389b36SDavid du Colombier } 200bd389b36SDavid du Colombier 201bd389b36SDavid du Colombier if (seek(datafd, 0L, 0) < 0) { 202bd389b36SDavid du Colombier error(0, "error seeking temp file\n"); 203bd389b36SDavid du Colombier exits("seek error"); 204bd389b36SDavid du Colombier } 205bd389b36SDavid du Colombier /* mirror performance in readfile() in lpdaemon */ 206bd389b36SDavid du Colombier atnotify(alarmhandler, 1); 207bd389b36SDavid du Colombier dbgstate = 1; 208bd389b36SDavid du Colombier if(!recvACK(netfd)) { 209bd389b36SDavid du Colombier error(0, "failed to receive ACK before sending data\n"); 210bd389b36SDavid du Colombier exits("recv ack1 failed"); 211bd389b36SDavid du Colombier } 212bd389b36SDavid du Colombier dbgstate = 2; 213bd389b36SDavid du Colombier if ((i=pass(datafd, netfd, bsize)) != 0) { 214bd389b36SDavid du Colombier NAK(netfd); 215bd389b36SDavid du Colombier error(0, "failed to send %d bytes\n", i); 216bd389b36SDavid du Colombier exits("send data failed"); 217bd389b36SDavid du Colombier } 218bd389b36SDavid du Colombier ACK(netfd); 219bd389b36SDavid du Colombier dbgstate = 3; 220bd389b36SDavid du Colombier if(!recvACK(netfd)) { 221bd389b36SDavid du Colombier error(0, "failed to receive ACK after sending data\n"); 222bd389b36SDavid du Colombier exits("recv ack2 failed"); 223bd389b36SDavid du Colombier } 224bd389b36SDavid du Colombier 225bd389b36SDavid du Colombier /* get response, as from lp -q */ 226bd389b36SDavid du Colombier dbgstate = 4; 227bd389b36SDavid du Colombier while((rv=read(netfd, jobbuf, RDSIZE)) > 0) { 228bd389b36SDavid du Colombier if((write(1, jobbuf, rv)) != rv) { 229bd389b36SDavid du Colombier error(0, "write error while sending to stdout\n"); 230bd389b36SDavid du Colombier exits("write error while sending to stdout"); 231bd389b36SDavid du Colombier } 232bd389b36SDavid du Colombier } 233bd389b36SDavid du Colombier dbgstate = 5; 234bd389b36SDavid du Colombier atnotify(alarmhandler, 0); 235bd389b36SDavid du Colombier /* close down network connections and go away */ 236bd389b36SDavid du Colombier exits(""); 237bd389b36SDavid du Colombier } 238