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