plan9port

fork of plan9port with libvec, libstr and libsdb
Log | Files | Refs | README | LICENSE

lpsend.c (6202B)


      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 	va_end(ap);
     72 	fprint(stderr, s1, *args);
     73 	return;
     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 	return;
    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 int tindx = 0;
    184 	char tmpf[20];
    185 	int tmpfd;
    186 
    187 	sprint(tmpf, "/var/tmp/lp%d.%d", getpid(), tindx++);
    188 	if((tmpfd=create(tmpf,
    189 
    190 #ifdef plan9
    191 
    192 						ORDWR|OTRUNC,
    193 
    194 #endif
    195 
    196 												0666)) < 0) {
    197 		error(0, "cannot create temp file %s\n", tmpf);
    198 		exits("cannot create temp file");
    199 	}
    200 	close(tmpfd);
    201 	if((tmpfd=open(tmpf, ORDWR
    202 
    203 #ifdef plan9
    204 
    205 						|ORCLOSE|OTRUNC
    206 
    207 #endif
    208 
    209 									)) < 0) {
    210 		error(0, "cannot open temp file %s\n", tmpf);
    211 		exits("cannot open temp file");
    212 	}
    213 	return(tmpfd);
    214 }
    215 
    216 int
    217 recvACK(int netfd)
    218 {
    219 	int rv;
    220 
    221 	*jobbuf = '\0';
    222 	alarm(RDNETIMEOUT);
    223 	if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {
    224 		error(0, "failed to receive ACK, ");
    225 		if (*jobbuf == '\0')
    226 			error(1, "read failed\n");
    227 		else
    228 			error(1, "received <0x%x> instead\n", *jobbuf);
    229 		rv = 0;
    230 	} else rv = 1;
    231 	alarm(0);
    232 	return(rv);
    233 }
    234 
    235 void
    236 main(int argc, char *argv[])
    237 {
    238 	char *devdir;
    239 	int i, rv, netfd, bsize;
    240 	int datafd;
    241 
    242 #ifndef plan9
    243 
    244 	void (*oldhandler)();
    245 
    246 #endif
    247 
    248 	devdir = nil;
    249 	/* make connection */
    250 	if (argc != 2) {
    251 		fprint(stderr, "usage: %s network!destination!service\n", argv[0]);
    252 		exits("incorrect number of arguments");
    253 	}
    254 
    255 	/* read options line from stdin into lnbuf */
    256 	i = readline(0);
    257 
    258 	/* read stdin into tempfile to get size */
    259 	datafd = tempfile();
    260 	bsize = prereadfile(datafd);
    261 
    262 	/* network connection is opened after data is in to avoid timeout */
    263 	if ((netfd=dial(argv[1], 0, 0, 0)) < 0) {
    264 		fprint(stderr, "dialing %s\n", devdir);
    265 		perror("dial");
    266 		exits("can't dial");
    267 	}
    268 
    269 	/* write out the options we read above */
    270 	if (write(netfd, lnbuf, i) != i) {
    271 		error(0, "write error while sending options\n");
    272 		exits("write error while sending options");
    273 	}
    274 
    275 	/* send the size of the file to be sent */
    276 	sprint(lnbuf, "%d\n", bsize);
    277 	i = strlen(lnbuf);
    278 	if ((rv=write(netfd, lnbuf, i)) != i) {
    279 		perror("write error while sending size");
    280 		error(0, "write returned %d\n", rv);
    281 		exits("write error while sending size");
    282 	}
    283 
    284 	if (seek(datafd, 0L, 0) < 0) {
    285 		error(0, "error seeking temp file\n");
    286 		exits("seek error");
    287 	}
    288 	/* mirror performance in readfile() in lpdaemon */
    289 
    290 #ifdef plan9
    291 
    292 	atnotify(alarmhandler, 1);
    293 
    294 #else
    295 
    296 	oldhandler = signal(SIGALRM, alarmhandler);
    297 
    298 #endif
    299 
    300 	dbgstate = 1;
    301 	if(!recvACK(netfd)) {
    302 		error(0, "failed to receive ACK before sending data\n");
    303 		exits("recv ack1 failed");
    304 	}
    305 	dbgstate = 2;
    306 	if ((i=pass(datafd, netfd, bsize)) != 0) {
    307 		NAK(netfd);
    308 		error(0, "failed to send %d bytes\n", i);
    309 		exits("send data failed");
    310 	}
    311 	ACK(netfd);
    312 	dbgstate = 3;
    313 	if(!recvACK(netfd)) {
    314 		error(0, "failed to receive ACK after sending data\n");
    315 		exits("recv ack2 failed");
    316 	}
    317 
    318 	/* get response, as from lp -q */
    319 	dbgstate = 4;
    320 	while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
    321 		if((write(1, jobbuf, rv)) != rv) {
    322 			error(0, "write error while sending to stdout\n");
    323 			exits("write error while sending to stdout");
    324 		}
    325 	}
    326 	dbgstate = 5;
    327 
    328 #ifdef plan9
    329 
    330 	atnotify(alarmhandler, 0);
    331 	/* close down network connections and go away */
    332 	exits("");
    333 
    334 #else
    335 
    336 	signal(SIGALRM, oldhandler);
    337 	exit(0);
    338 
    339 #endif
    340 
    341 }