327 lines · 6.3 KB · C
RawDownload
/*  * This file is part of the UCB release of Plan 9. It is subject to the license * terms in the LICENSE file found in the top-level directory of this * distribution and at http://akaros.cs.berkeley.edu/files/Plan9License. No * part of the UCB release of Plan 9, including this file, may be copied, * modified, propagated, or distributed except according to the terms contained * in the LICENSE file. */ #ifdef plan9 #include <u.h>#include <libc.h> enum {	stderr = 2,	RDNETIMEOUT = 30*60*1000,	WRNETIMEOUT = RDNETIMEOUT,};#else /* not for plan 9 */#include <stdio.h>#include <errno.h>#include <time.h>#include <fcntl.h>#include <signal.h> #define	create	creat#define	seek	lseek#define	fprint	fprintf#define	sprint	sprintf#define	exits	exit #define	ORDWR	O_RDWR#define	OTRUNC	O_TRUNC#define	ORCLOSE	0 #define RDNETIMEOUT	60#define WRNETIMEOUT	60 #endif #define MIN(a,b)	((a<b)?a:b) #define	ACK(a)	write(a, "", 1)#define NAK(a)	write(a, "\001", 1) #define LPDAEMONLOG	"/tmp/lpdaemonl" #define LNBFSZ	4096char lnbuf[LNBFSZ];int dbgstate = 0;char *dbgstrings[] = {	"",	"rcvack1",	"send",	"rcvack2",	"response",	"done"}; #ifdef plan9 voiderror(int level, char *s1, ...){	va_list ap;	long thetime;	char *chartime;	char *args[8];	int argno = 0; 	if (level == 0) {		time(&thetime);		chartime = ctime(thetime);		fprint(stderr, "%.15s ", &(chartime[4]));	}	va_start(ap, s1);	while(args[argno++] = va_arg(ap, char*))		;	va_end(ap);	fprint(stderr, s1, *args);} intalarmhandler(void *foo, char *note) {	USED(foo);	if(strcmp(note, "alarm")==0) {		fprint(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);		return(1);	} else return(0);} #else voiderror(int level, char *s1, ...){	time_t thetime;	char *chartime; 	if (level == 0) {		time(&thetime);		chartime = ctime(&thetime);		fprintf(stderr, "%.15s ", &(chartime[4]));	}	fprintf(stderr, s1, &s1 + 1);} voidalarmhandler() {	fprintf(stderr, "alarm at %d - %s\n", dbgstate, dbgstrings[dbgstate]);} #endif /* get a line from inpfd using nonbuffered input.  The line is truncated if it is too * long for the buffer.  The result is left in lnbuf and the number of characters * read in is returned. */intreadline(int inpfd){	register char *ap;	register int i; 	ap = lnbuf;	i = 0;	do {		if (read(inpfd, ap, 1) != 1) {			error(0, "read error in readline, fd=%d\n", inpfd);			break;		}	} while ((++i < LNBFSZ - 2) && *ap++ != '\n');	if (i == LNBFSZ - 2) {		*ap = '\n';		i++;	}	*ap = '\0';	return(i);} #define	RDSIZE 512char jobbuf[RDSIZE]; intpass(int inpfd, int outfd, int bsize){	int rv, bcnt; 	for(bcnt=bsize; bcnt > 0; bcnt -= rv) {		alarm(WRNETIMEOUT);	/* to break hanging */		if((rv=read(inpfd, jobbuf, MIN(bcnt,RDSIZE))) < 0) {			error(0, "read error during pass, %d remaining\n", bcnt);			break;		} else if((write(outfd, jobbuf, rv)) != rv) {			error(0, "write error during pass, %d remaining\n", bcnt);			break;		}	}	alarm(0);	return(bcnt);}	/* get whatever stdin has and put it into the temporary file. * return the file size. */intprereadfile(int inpfd){	int rv, bsize; 	bsize = 0;	do {		if((rv=read(0, jobbuf, RDSIZE))<0) {			error(0, "read error while making temp file\n");			exits("read error while making temp file");		} else if((write(inpfd, jobbuf, rv)) != rv) {			error(0, "write error while making temp file\n");			exits("write error while making temp file");		}		bsize += rv;	} while (rv!=0);	return(bsize);} inttempfile(void){	static tindx = 0;	char tmpf[20];	int tmpfd; 	sprint(tmpf, "/tmp/lp%d.%d", getpid(), tindx++);	if((tmpfd=create(tmpf,#ifdef plan9		ORDWR|OTRUNC,#endif	    0666)) < 0) {		error(0, "cannot create temp file %s\n", tmpf);		exits("cannot create temp file");	}	close(tmpfd);	if((tmpfd=open(tmpf, ORDWR#ifdef plan9		|ORCLOSE|OTRUNC#endif	    )) < 0) {		error(0, "cannot open temp file %s\n", tmpf);		exits("cannot open temp file");	}	return(tmpfd);} intrecvACK(int netfd){	int rv; 	*jobbuf = '\0';	alarm(RDNETIMEOUT);	if (read(netfd, jobbuf, 1)!=1 || *jobbuf!='\0') {		error(0, "failed to receive ACK, ");		if (*jobbuf == '\0')			error(1, "read failed\n");		else			error(1, "received <%#x> instead\n", (uchar)*jobbuf);		rv = 0;	} else rv = 1;	alarm(0);	return(rv);} voidmain(int argc, char *argv[]){	int i, rv, netfd, bsize, datafd;#ifndef plan9	void (*oldhandler)();#endif 	/* make connection */	if (argc != 2) {		fprint(stderr, "usage: %s network!destination!service\n",			argv[0]);		exits("usage");	} 	/* read options line from stdin into lnbuf */	i = readline(0); 	/* read stdin into tempfile to get size */	datafd = tempfile();	bsize = prereadfile(datafd); 	/* network connection is opened after data is in to avoid timeout */	if ((netfd = dial(argv[1], 0, 0, 0)) < 0) {		fprint(stderr, "dialing ");		perror(argv[1]);		exits("can't dial");	} 	/* write out the options we read above */	if (write(netfd, lnbuf, i) != i) {		error(0, "write error while sending options\n");		exits("write error sending options");	} 	/* send the size of the file to be sent */	sprint(lnbuf, "%d\n", bsize);	i = strlen(lnbuf);	if ((rv=write(netfd, lnbuf, i)) != i) {		perror("write error while sending size");		error(0, "write returned %d\n", rv);		exits("write error sending size");	} 	if (seek(datafd, 0L, 0) < 0) {		error(0, "error seeking temp file\n");		exits("seek error");	}	/* mirror performance in readfile() in lpdaemon */ #ifdef plan9	atnotify(alarmhandler, 1);#else	oldhandler = signal(SIGALRM, alarmhandler);#endif 	dbgstate = 1;	if(!recvACK(netfd)) {		error(0, "failed to receive ACK before sending data\n");		exits("recv ack1 failed");	}	dbgstate = 2;	if ((i=pass(datafd, netfd, bsize)) != 0) {		NAK(netfd);		error(0, "failed to send %d bytes\n", i);		exits("send data failed");	}	ACK(netfd);	dbgstate = 3;	if(!recvACK(netfd)) {		error(0, "failed to receive ACK after sending data\n");		exits("recv ack2 failed");	} 	/* get response, as from lp -q */	dbgstate = 4;	while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {		if((write(1, jobbuf, rv)) != rv) {			error(0, "write error while sending to stdout\n");			exits("write error while sending to stdout");		}	}	dbgstate = 5; #ifdef plan9	atnotify(alarmhandler, 0);	/* close down network connections and go away */	exits("");#else	signal(SIGALRM, oldhandler);	exit(0);#endif}