1 #ifdef plan9 2 3 #include <u.h> 4 #include <libc.h> 5 #define stderr 2 6 7 #define RDNETIMEOUT 60000 8 #define WRNETIMEOUT 60000 9 10 #else 11 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> 18 19 #define create creat 20 #define seek lseek 21 #define fprint fprintf 22 #define sprint sprintf 23 #define exits exit 24 25 #define ORDWR O_RDWR 26 #define OTRUNC O_TRUNC 27 #define ORCLOSE 0 28 29 #define RDNETIMEOUT 60 30 #define WRNETIMEOUT 60 31 32 #endif 33 34 #define MIN(a,b) ((a<b)?a:b) 35 36 #define ACK(a) write(a, "", 1) 37 #define NAK(a) write(a, "\001", 1) 38 39 #define LPDAEMONLOG "/tmp/lpdaemonl" 40 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 }; 52 53 #ifdef plan9 54 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; 63 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 ; 72 va_end(ap); 73 fprint(stderr, s1, *args); 74 } 75 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 } 84 85 #else 86 87 void 88 error(int level, char *s1, ...) 89 { 90 time_t thetime; 91 char *chartime; 92 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 } 100 101 void 102 alarmhandler() { 103 fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]); 104 } 105 106 #endif 107 108 /* get a line from inpfd using nonbuffered input. The line is truncated if it is too 109 * long for the buffer. The result is left in lnbuf and the number of characters 110 * read in is returned. 111 */ 112 int 113 readline(int inpfd) 114 { 115 register char *ap; 116 register int i; 117 118 ap = lnbuf; 119 i = 0; 120 do { 121 if (read(inpfd, ap, 1) != 1) { 122 error(0, "read error in readline, fd=%d\n", inpfd); 123 break; 124 } 125 } while ((++i < LNBFSZ - 2) && *ap++ != '\n'); 126 if (i == LNBFSZ - 2) { 127 *ap = '\n'; 128 i++; 129 } 130 *ap = '\0'; 131 return(i); 132 } 133 134 #define RDSIZE 512 135 char jobbuf[RDSIZE]; 136 137 int 138 pass(int inpfd, int outfd, int bsize) 139 { 140 int bcnt = 0; 141 int rv = 0; 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 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 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 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 <0x%x> instead\n", *jobbuf); 220 rv = 0; 221 } else rv = 1; 222 alarm(0); 223 return(rv); 224 } 225 226 void 227 main(int argc, char *argv[]) 228 { 229 char *devdir; 230 int i, rv, netfd, bsize; 231 int datafd; 232 233 #ifndef plan9 234 235 void (*oldhandler)(); 236 237 #endif 238 239 /* make connection */ 240 if (argc != 2) { 241 fprint(stderr, "usage: %s network!destination!service\n", argv[0]); 242 exits("incorrect number of arguments"); 243 } 244 245 /* read options line from stdin into lnbuf */ 246 i = readline(0); 247 248 /* read stdin into tempfile to get size */ 249 datafd = tempfile(); 250 bsize = prereadfile(datafd); 251 252 /* network connection is opened after data is in to avoid timeout */ 253 if ((netfd=dial(argv[1], 0, 0, 0)) < 0) { 254 fprint(stderr, "dialing %s\n", devdir); 255 perror("dial"); 256 exits("can't dial"); 257 } 258 259 /* write out the options we read above */ 260 if (write(netfd, lnbuf, i) != i) { 261 error(0, "write error while sending options\n"); 262 exits("write error while sending options"); 263 } 264 265 /* send the size of the file to be sent */ 266 sprint(lnbuf, "%d\n", bsize); 267 i = strlen(lnbuf); 268 if ((rv=write(netfd, lnbuf, i)) != i) { 269 perror("write error while sending size"); 270 error(0, "write returned %d\n", rv); 271 exits("write error while sending size"); 272 } 273 274 if (seek(datafd, 0L, 0) < 0) { 275 error(0, "error seeking temp file\n"); 276 exits("seek error"); 277 } 278 /* mirror performance in readfile() in lpdaemon */ 279 280 #ifdef plan9 281 282 atnotify(alarmhandler, 1); 283 284 #else 285 286 oldhandler = signal(SIGALRM, alarmhandler); 287 288 #endif 289 290 dbgstate = 1; 291 if(!recvACK(netfd)) { 292 error(0, "failed to receive ACK before sending data\n"); 293 exits("recv ack1 failed"); 294 } 295 dbgstate = 2; 296 if ((i=pass(datafd, netfd, bsize)) != 0) { 297 NAK(netfd); 298 error(0, "failed to send %d bytes\n", i); 299 exits("send data failed"); 300 } 301 ACK(netfd); 302 dbgstate = 3; 303 if(!recvACK(netfd)) { 304 error(0, "failed to receive ACK after sending data\n"); 305 exits("recv ack2 failed"); 306 } 307 308 /* get response, as from lp -q */ 309 dbgstate = 4; 310 while((rv=read(netfd, jobbuf, RDSIZE)) > 0) { 311 if((write(1, jobbuf, rv)) != rv) { 312 error(0, "write error while sending to stdout\n"); 313 exits("write error while sending to stdout"); 314 } 315 } 316 dbgstate = 5; 317 318 #ifdef plan9 319 320 atnotify(alarmhandler, 0); 321 /* close down network connections and go away */ 322 exits(""); 323 324 #else 325 326 signal(SIGALRM, oldhandler); 327 exit(0); 328 329 #endif 330 331 } 332