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 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 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 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 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 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 139 pass(int inpfd, int outfd, int bsize) 140 { 141 int bcnt = 0; 142 int rv = 0; 143 144 for(bcnt=bsize; bcnt > 0; bcnt -= rv) { 145 alarm(WRNETIMEOUT); /* to break hanging */ 146 if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) { 147 error(0, "read error during pass, %d remaining\n", bcnt); 148 break; 149 } else if((write(outfd, jobbuf, rv)) != rv) { 150 error(0, "write error during pass, %d remaining\n", bcnt); 151 break; 152 } 153 } 154 alarm(0); 155 return(bcnt); 156 } 157 158 /* get whatever stdin has and put it into the temporary file. 159 * return the file size. 160 */ 161 int 162 prereadfile(int inpfd) 163 { 164 int rv, bsize; 165 166 bsize = 0; 167 do { 168 if((rv=read(0, jobbuf, RDSIZE))<0) { 169 error(0, "read error while making temp file\n"); 170 exits("read error while making temp file"); 171 } else if((write(inpfd, jobbuf, rv)) != rv) { 172 error(0, "write error while making temp file\n"); 173 exits("write error while making temp file"); 174 } 175 bsize += rv; 176 } while (rv!=0); 177 return(bsize); 178 } 179 180 int 181 tempfile(void) 182 { 183 static tindx = 0; 184 char tmpf[20]; 185 int tmpfd; 186 187 sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++); 188 if((tmpfd=create(tmpf, 189 #ifdef plan9 190 ORDWR|OTRUNC, 191 #endif 192 0666)) < 0) { 193 error(0, "cannot create temp file %s\n", tmpf); 194 exits("cannot create temp file"); 195 } 196 close(tmpfd); 197 if((tmpfd=open(tmpf, ORDWR 198 #ifdef plan9 199 |ORCLOSE|OTRUNC 200 #endif 201 )) < 0) { 202 error(0, "cannot open temp file %s\n", tmpf); 203 exits("cannot open temp file"); 204 } 205 return(tmpfd); 206 } 207 208 int 209 recvACK(int netfd) 210 { 211 int rv; 212 213 *jobbuf = '\0'; 214 alarm(RDNETIMEOUT); 215 if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') { 216 error(0, "failed to receive ACK, "); 217 if (*jobbuf == '\0') 218 error(1, "read failed\n"); 219 else 220 error(1, "received <0x%x> instead\n", *jobbuf); 221 rv = 0; 222 } else rv = 1; 223 alarm(0); 224 return(rv); 225 } 226 227 void 228 main(int argc, char *argv[]) 229 { 230 char *devdir; 231 int i, rv, netfd, bsize, datafd; 232 #ifndef plan9 233 void (*oldhandler)(); 234 #endif 235 236 /* make connection */ 237 if (argc != 2) { 238 fprint(stderr, "usage: %s network!destination!service\n", 239 argv[0]); 240 exits("usage"); 241 } 242 243 /* read options line from stdin into lnbuf */ 244 i = readline(0); 245 246 /* read stdin into tempfile to get size */ 247 datafd = tempfile(); 248 bsize = prereadfile(datafd); 249 250 /* network connection is opened after data is in to avoid timeout */ 251 if ((netfd = dial(argv[1], 0, 0, 0)) < 0) { 252 fprint(stderr, "dialing "); 253 perror(argv[1]); 254 exits("can't dial"); 255 } 256 257 /* write out the options we read above */ 258 if (write(netfd, lnbuf, i) != i) { 259 error(0, "write error while sending options\n"); 260 exits("write error sending options"); 261 } 262 263 /* send the size of the file to be sent */ 264 sprint(lnbuf, "%d\n", bsize); 265 i = strlen(lnbuf); 266 if ((rv=write(netfd, lnbuf, i)) != i) { 267 perror("write error while sending size"); 268 error(0, "write returned %d\n", rv); 269 exits("write error sending size"); 270 } 271 272 if (seek(datafd, 0L, 0) < 0) { 273 error(0, "error seeking temp file\n"); 274 exits("seek error"); 275 } 276 /* mirror performance in readfile() in lpdaemon */ 277 278 #ifdef plan9 279 atnotify(alarmhandler, 1); 280 #else 281 oldhandler = signal(SIGALRM, alarmhandler); 282 #endif 283 284 dbgstate = 1; 285 if(!recvACK(netfd)) { 286 error(0, "failed to receive ACK before sending data\n"); 287 exits("recv ack1 failed"); 288 } 289 dbgstate = 2; 290 if ((i=pass(datafd, netfd, bsize)) != 0) { 291 NAK(netfd); 292 error(0, "failed to send %d bytes\n", i); 293 exits("send data failed"); 294 } 295 ACK(netfd); 296 dbgstate = 3; 297 if(!recvACK(netfd)) { 298 error(0, "failed to receive ACK after sending data\n"); 299 exits("recv ack2 failed"); 300 } 301 302 /* get response, as from lp -q */ 303 dbgstate = 4; 304 while((rv=read(netfd, jobbuf, RDSIZE)) > 0) { 305 if((write(1, jobbuf, rv)) != rv) { 306 error(0, "write error while sending to stdout\n"); 307 exits("write error while sending to stdout"); 308 } 309 } 310 dbgstate = 5; 311 312 #ifdef plan9 313 atnotify(alarmhandler, 0); 314 /* close down network connections and go away */ 315 exits(""); 316 #else 317 signal(SIGALRM, oldhandler); 318 exit(0); 319 #endif 320 } 321