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