Subversion Repositories planix.SVN

Rev

Rev 2 | Details | Compare with Previous | Last modification | View Log | RSS feed

Rev Author Line No. Line
2 - 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 rv, bcnt;
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 <%#x> instead\n", (uchar)*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
	int i, rv, netfd, bsize, datafd;
230
#ifndef plan9
231
	void (*oldhandler)();
232
#endif
233
 
234
	/* make connection */
235
	if (argc != 2) {
236
		fprint(stderr, "usage: %s network!destination!service\n",
237
			argv[0]);
238
		exits("usage");
239
	}
240
 
241
	/* read options line from stdin into lnbuf */
242
	i = readline(0);
243
 
244
	/* read stdin into tempfile to get size */
245
	datafd = tempfile();
246
	bsize = prereadfile(datafd);
247
 
248
	/* network connection is opened after data is in to avoid timeout */
249
	if ((netfd = dial(argv[1], 0, 0, 0)) < 0) {
250
		fprint(stderr, "dialing ");
251
		perror(argv[1]);
252
		exits("can't dial");
253
	}
254
 
255
	/* write out the options we read above */
256
	if (write(netfd, lnbuf, i) != i) {
257
		error(0, "write error while sending options\n");
258
		exits("write error sending options");
259
	}
260
 
261
	/* send the size of the file to be sent */
262
	sprint(lnbuf, "%d\n", bsize);
263
	i = strlen(lnbuf);
264
	if ((rv=write(netfd, lnbuf, i)) != i) {
265
		perror("write error while sending size");
266
		error(0, "write returned %d\n", rv);
267
		exits("write error sending size");
268
	}
269
 
270
	if (seek(datafd, 0L, 0) < 0) {
271
		error(0, "error seeking temp file\n");
272
		exits("seek error");
273
	}
274
	/* mirror performance in readfile() in lpdaemon */
275
 
276
#ifdef plan9
277
	atnotify(alarmhandler, 1);
278
#else
279
	oldhandler = signal(SIGALRM, alarmhandler);
280
#endif
281
 
282
	dbgstate = 1;
283
	if(!recvACK(netfd)) {
284
		error(0, "failed to receive ACK before sending data\n");
285
		exits("recv ack1 failed");
286
	}
287
	dbgstate = 2;
288
	if ((i=pass(datafd, netfd, bsize)) != 0) {
289
		NAK(netfd);
290
		error(0, "failed to send %d bytes\n", i);
291
		exits("send data failed");
292
	}
293
	ACK(netfd);
294
	dbgstate = 3;
295
	if(!recvACK(netfd)) {
296
		error(0, "failed to receive ACK after sending data\n");
297
		exits("recv ack2 failed");
298
	}
299
 
300
	/* get response, as from lp -q */
301
	dbgstate = 4;
302
	while((rv=read(netfd, jobbuf, RDSIZE)) > 0) {
303
		if((write(1, jobbuf, rv)) != rv) {
304
			error(0, "write error while sending to stdout\n");
305
			exits("write error while sending to stdout");
306
		}
307
	}
308
	dbgstate = 5;
309
 
310
#ifdef plan9
311
	atnotify(alarmhandler, 0);
312
	/* close down network connections and go away */
313
	exits("");
314
#else
315
	signal(SIGALRM, oldhandler);
316
	exit(0);
317
#endif
318
}