xref: /csrg-svn/usr.bin/tftp/tftp.c (revision 7770)
1*7770Ssam /*	tftp.c	4.1	82/08/16	*/
2*7770Ssam 
3*7770Ssam /*
4*7770Ssam  * TFTP User Program -- Protocol Machines
5*7770Ssam  */
6*7770Ssam #include <sys/types.h>
7*7770Ssam #include <net/in.h>
8*7770Ssam #include <sys/socket.h>
9*7770Ssam #include <signal.h>
10*7770Ssam #include <stdio.h>
11*7770Ssam #include <errno.h>
12*7770Ssam #include <setjmp.h>
13*7770Ssam #include "tftp.h"
14*7770Ssam 
15*7770Ssam extern	int errno;
16*7770Ssam extern	struct sockaddr_in sin;
17*7770Ssam extern	char mode[];
18*7770Ssam int	f;
19*7770Ssam int	trace;
20*7770Ssam int	verbose;
21*7770Ssam int	connected;
22*7770Ssam char	buf[BUFSIZ];
23*7770Ssam int	timeout;
24*7770Ssam jmp_buf	toplevel;
25*7770Ssam 
26*7770Ssam timer()
27*7770Ssam {
28*7770Ssam 	timeout += TIMEOUT;
29*7770Ssam 	if (timeout >= MAXTIMEOUT) {
30*7770Ssam 		printf("Transfer timed out.\n");
31*7770Ssam 		longjmp(toplevel, -1);
32*7770Ssam 	}
33*7770Ssam 	alarm(TIMEOUT);
34*7770Ssam }
35*7770Ssam 
36*7770Ssam /*
37*7770Ssam  * Send the requested file.
38*7770Ssam  */
39*7770Ssam sendfile(fd, name)
40*7770Ssam 	int fd;
41*7770Ssam 	char *name;
42*7770Ssam {
43*7770Ssam 	register struct tftphdr *tp = (struct tftphdr *)buf;
44*7770Ssam 	register int block = 0, size, n, amount = 0;
45*7770Ssam 	struct sockaddr_in from;
46*7770Ssam 	time_t start = time(0), delta;
47*7770Ssam 
48*7770Ssam 	size = makerequest(WRQ, name) - 4;
49*7770Ssam 	sigset(SIGALRM, timer);
50*7770Ssam 	do {
51*7770Ssam 		if (block != 0) {
52*7770Ssam 			size = read(fd, tp->th_data, SEGSIZE);
53*7770Ssam 			if (size < 0) {
54*7770Ssam 				nak(errno + 100);
55*7770Ssam 				break;
56*7770Ssam 			}
57*7770Ssam 			tp->th_opcode = htons((u_short)DATA);
58*7770Ssam 			tp->th_block = htons((u_short)block);
59*7770Ssam 		}
60*7770Ssam 		timeout = 0;
61*7770Ssam 		alarm(TIMEOUT);
62*7770Ssam rexmt:
63*7770Ssam 		if (trace)
64*7770Ssam 			tpacket("sent", tp, size + 4);
65*7770Ssam 		if (send(f, &sin, buf, size + 4) != size + 4) {
66*7770Ssam 			perror("send");
67*7770Ssam 			break;
68*7770Ssam 		}
69*7770Ssam again:
70*7770Ssam 		n = receive(f, &from, buf, sizeof (buf));
71*7770Ssam 		if (n <= 0) {
72*7770Ssam 			if (n == 0)
73*7770Ssam 				goto again;
74*7770Ssam 			if (errno == EINTR)
75*7770Ssam 				goto rexmt;
76*7770Ssam 			alarm(0);
77*7770Ssam 			perror("receive");
78*7770Ssam 			break;
79*7770Ssam 		}
80*7770Ssam 		alarm(0);
81*7770Ssam 		if (trace)
82*7770Ssam 			tpacket("received", tp, n);
83*7770Ssam #if vax || pdp11
84*7770Ssam 		tp->th_opcode = ntohs(tp->th_opcode);
85*7770Ssam 		tp->th_block = ntohs(tp->th_block);
86*7770Ssam #endif
87*7770Ssam 		if (tp->th_opcode == ERROR) {
88*7770Ssam 			printf("Error code %d: %s\n", tp->th_code,
89*7770Ssam 				tp->th_msg);
90*7770Ssam 			break;
91*7770Ssam 		}
92*7770Ssam 		if (tp->th_opcode != ACK || block != tp->th_block)
93*7770Ssam 			goto again;
94*7770Ssam 		if (block > 0)
95*7770Ssam 			amount += size;
96*7770Ssam 		block++;
97*7770Ssam 	} while (size == SEGSIZE || block == 1);
98*7770Ssam 	alarm(0);
99*7770Ssam 	(void) close(fd);
100*7770Ssam 	if (amount > 0) {
101*7770Ssam 		delta = time(0) - start;
102*7770Ssam 		printf("Sent %d bytes in %d seconds.\n", amount, delta);
103*7770Ssam 	}
104*7770Ssam }
105*7770Ssam 
106*7770Ssam /*
107*7770Ssam  * Receive a file.
108*7770Ssam  */
109*7770Ssam recvfile(fd, name)
110*7770Ssam 	int fd;
111*7770Ssam 	char *name;
112*7770Ssam {
113*7770Ssam 	register struct tftphdr *tp = (struct tftphdr *)buf;
114*7770Ssam 	register int block = 1, n, size, amount = 0;
115*7770Ssam 	struct sockaddr_in from;
116*7770Ssam 	time_t start = time(0), delta;
117*7770Ssam 
118*7770Ssam 	size = makerequest(RRQ, name);
119*7770Ssam 	sigset(SIGALRM, timer);
120*7770Ssam 	alarm(TIMEOUT);
121*7770Ssam 	goto rexmt;
122*7770Ssam 	do {
123*7770Ssam 		timeout = 0;
124*7770Ssam 		alarm(TIMEOUT);
125*7770Ssam 		tp->th_opcode = htons((u_short)ACK);
126*7770Ssam 		tp->th_block = htons((u_short)(block));
127*7770Ssam 		size = 4;
128*7770Ssam 		block++;
129*7770Ssam rexmt:
130*7770Ssam 		if (trace)
131*7770Ssam 			tpacket("sent", tp, size);
132*7770Ssam 		if (send(f, &sin, buf, size) != size) {
133*7770Ssam 			perror("send");
134*7770Ssam 			break;
135*7770Ssam 		}
136*7770Ssam again:
137*7770Ssam 		n = receive(f, &from, buf, sizeof (buf));
138*7770Ssam 		if (n <= 0) {
139*7770Ssam 			if (n == 0)
140*7770Ssam 				goto again;
141*7770Ssam 			if (errno == EINTR)
142*7770Ssam 				goto rexmt;
143*7770Ssam 			alarm(0);
144*7770Ssam 			perror("receive");
145*7770Ssam 			break;
146*7770Ssam 		}
147*7770Ssam 		alarm(0);
148*7770Ssam 		if (trace)
149*7770Ssam 			tpacket("received", tp, n);
150*7770Ssam #if vax || pdp11
151*7770Ssam 		tp->th_opcode = ntohs(tp->th_opcode);
152*7770Ssam 		tp->th_block = ntohs(tp->th_block);
153*7770Ssam #endif
154*7770Ssam 		if (tp->th_opcode == ERROR) {
155*7770Ssam 			printf("Error code %d: %s\n", tp->th_code,
156*7770Ssam 				tp->th_msg);
157*7770Ssam 			break;
158*7770Ssam 		}
159*7770Ssam 		if (tp->th_opcode != DATA || block != tp->th_block)
160*7770Ssam 			goto again;
161*7770Ssam 		size = write(fd, tp->th_data, n - 4);
162*7770Ssam 		if (size < 0) {
163*7770Ssam 			nak(errno + 100);
164*7770Ssam 			break;
165*7770Ssam 		}
166*7770Ssam 		amount += size;
167*7770Ssam 	} while (size == SEGSIZE);
168*7770Ssam 	alarm(0);
169*7770Ssam 	tp->th_opcode = htons((u_short)ACK);
170*7770Ssam 	tp->th_block = htons((u_short)block);
171*7770Ssam 	(void) send(f, &sin, buf, 4);
172*7770Ssam 	(void) close(fd);
173*7770Ssam 	if (amount > 0) {
174*7770Ssam 		delta = time(0) - start;
175*7770Ssam 		printf("Received %d bytes in %d seconds.\n", amount, delta);
176*7770Ssam 	}
177*7770Ssam }
178*7770Ssam 
179*7770Ssam makerequest(request, name)
180*7770Ssam 	int request;
181*7770Ssam 	char *name;
182*7770Ssam {
183*7770Ssam 	register struct tftphdr *tp;
184*7770Ssam 	int size;
185*7770Ssam 	register char *cp;
186*7770Ssam 
187*7770Ssam 	tp = (struct tftphdr *)buf;
188*7770Ssam 	tp->th_opcode = htons((u_short)request);
189*7770Ssam 	strcpy(tp->th_stuff, name);
190*7770Ssam 	size = strlen(name);
191*7770Ssam 	cp = tp->th_stuff + strlen(name);
192*7770Ssam 	*cp++ = '\0';
193*7770Ssam 	strcpy(cp, mode);
194*7770Ssam 	cp += sizeof ("netascii") - 1;
195*7770Ssam 	*cp++ = '\0';
196*7770Ssam 	return (cp - buf);
197*7770Ssam }
198*7770Ssam 
199*7770Ssam struct errmsg {
200*7770Ssam 	int	e_code;
201*7770Ssam 	char	*e_msg;
202*7770Ssam } errmsgs[] = {
203*7770Ssam 	{ EUNDEF,	"Undefined error code" },
204*7770Ssam 	{ ENOTFOUND,	"File not found" },
205*7770Ssam 	{ EACCESS,	"Access violation" },
206*7770Ssam 	{ ENOSPACE,	"Disk full or allocation exceeded" },
207*7770Ssam 	{ EBADOP,	"Illegal TFTP operation" },
208*7770Ssam 	{ EBADID,	"Unknown transfer ID" },
209*7770Ssam 	{ EEXISTS,	"File already exists" },
210*7770Ssam 	{ ENOUSER,	"No such user" },
211*7770Ssam 	{ -1,		0 }
212*7770Ssam };
213*7770Ssam 
214*7770Ssam /*
215*7770Ssam  * Send a nak packet (error message).
216*7770Ssam  * Error code passed in is one of the
217*7770Ssam  * standard TFTP codes, or a UNIX errno
218*7770Ssam  * offset by 100.
219*7770Ssam  */
220*7770Ssam nak(error)
221*7770Ssam 	int error;
222*7770Ssam {
223*7770Ssam 	register struct tftphdr *tp;
224*7770Ssam 	int length;
225*7770Ssam 	register struct errmsg *pe;
226*7770Ssam 	extern char *sys_errlist[];
227*7770Ssam 
228*7770Ssam 	tp = (struct tftphdr *)buf;
229*7770Ssam 	tp->th_opcode = htons((u_short)ERROR);
230*7770Ssam 	tp->th_code = htons((u_short)error);
231*7770Ssam 	for (pe = errmsgs; pe->e_code >= 0; pe++)
232*7770Ssam 		if (pe->e_code == error)
233*7770Ssam 			break;
234*7770Ssam 	if (pe->e_code < 0)
235*7770Ssam 		pe->e_msg = sys_errlist[error - 100];
236*7770Ssam 	strcpy(tp->th_msg, pe->e_msg);
237*7770Ssam 	length = strlen(pe->e_msg) + 4;
238*7770Ssam 	if (trace)
239*7770Ssam 		tpacket("sent", tp, length);
240*7770Ssam 	if (send(f, &sin, buf, length) != length)
241*7770Ssam 		perror("nak");
242*7770Ssam }
243*7770Ssam 
244*7770Ssam tpacket(s, tp, n)
245*7770Ssam 	struct tftphdr *tp;
246*7770Ssam 	int n;
247*7770Ssam {
248*7770Ssam 	static char *opcodes[] =
249*7770Ssam 	   { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
250*7770Ssam 	register char *cp, *file;
251*7770Ssam 	u_short op = ntohs(tp->th_opcode);
252*7770Ssam 	char *index();
253*7770Ssam 
254*7770Ssam 	if (op < RRQ || op > ERROR)
255*7770Ssam 		printf("%s opcode=%x ", s, op);
256*7770Ssam 	else
257*7770Ssam 		printf("%s %s ", s, opcodes[op]);
258*7770Ssam 	switch (op) {
259*7770Ssam 
260*7770Ssam 	case RRQ:
261*7770Ssam 	case WRQ:
262*7770Ssam 		n -= 2;
263*7770Ssam 		file = cp = tp->th_stuff;
264*7770Ssam 		cp = index(cp, '\0');
265*7770Ssam 		printf("<file=%s, mode=%s>\n", file, cp + 1);
266*7770Ssam 		break;
267*7770Ssam 
268*7770Ssam 	case DATA:
269*7770Ssam 		printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
270*7770Ssam 		break;
271*7770Ssam 
272*7770Ssam 	case ACK:
273*7770Ssam 		printf("<block=%d>\n", ntohs(tp->th_block));
274*7770Ssam 		break;
275*7770Ssam 
276*7770Ssam 	case ERROR:
277*7770Ssam 		printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
278*7770Ssam 		break;
279*7770Ssam 	}
280*7770Ssam }
281