add imagen
[unix-history] / usr / src / usr.bin / tftp / tftp.c
CommitLineData
d0aeaf5a
DF
1/*
2 * Copyright (c) 1983 Regents of the University of California.
3 * All rights reserved. The Berkeley software License Agreement
4 * specifies the terms and conditions for redistribution.
5 */
6
524aa063 7#ifndef lint
d0aeaf5a
DF
8static char sccsid[] = "@(#)tftp.c 5.1 (Berkeley) %G%";
9#endif not lint
d3fc13cc
SL
10
11/*
12 * TFTP User Program -- Protocol Machines
13 */
14#include <sys/types.h>
d3fc13cc 15#include <sys/socket.h>
de3b21e8
SL
16
17#include <netinet/in.h>
fc945f1a 18#include <arpa/inet.h>
86fe57d4
SL
19#include <arpa/tftp.h>
20
d3fc13cc
SL
21#include <signal.h>
22#include <stdio.h>
23#include <errno.h>
24#include <setjmp.h>
fc945f1a 25#include <netdb.h>
de3b21e8 26
d3fc13cc
SL
27extern int errno;
28extern struct sockaddr_in sin;
29extern char mode[];
30int f;
31int trace;
d3fc13cc 32int connected;
debfddc0
SL
33char sbuf[BUFSIZ]; /* send buffer */
34char rbuf[BUFSIZ]; /* receive buffer */
61ad9979
SL
35int rexmtval;
36int maxtimeout;
d3fc13cc
SL
37int timeout;
38jmp_buf toplevel;
61ad9979 39jmp_buf timeoutbuf;
d3fc13cc
SL
40
41timer()
42{
61ad9979
SL
43
44 timeout += rexmtval;
45 if (timeout >= maxtimeout) {
d3fc13cc
SL
46 printf("Transfer timed out.\n");
47 longjmp(toplevel, -1);
48 }
61ad9979 49 longjmp(timeoutbuf, 1);
d3fc13cc
SL
50}
51
52/*
53 * Send the requested file.
54 */
55sendfile(fd, name)
56 int fd;
57 char *name;
58{
debfddc0
SL
59 register struct tftphdr *stp = (struct tftphdr *)sbuf;
60 register struct tftphdr *rtp = (struct tftphdr *)rbuf;
d3fc13cc 61 register int block = 0, size, n, amount = 0;
fc945f1a 62 struct sockaddr_in from, to;
d3fc13cc 63 time_t start = time(0), delta;
fc945f1a 64 int fromlen, aborted = 0;
d3fc13cc 65
fc945f1a 66 to = sin;
61ad9979 67 signal(SIGALRM, timer);
d3fc13cc 68 do {
61ad9979
SL
69 if (block == 0)
70 size = makerequest(WRQ, name) - 4;
71 else {
debfddc0 72 size = read(fd, stp->th_data, SEGSIZE);
d3fc13cc 73 if (size < 0) {
fc945f1a 74 nak(&to, errno + 100);
d3fc13cc
SL
75 break;
76 }
debfddc0
SL
77 stp->th_opcode = htons((u_short)DATA);
78 stp->th_block = htons((u_short)block);
d3fc13cc
SL
79 }
80 timeout = 0;
61ad9979 81 (void) setjmp(timeoutbuf);
d3fc13cc 82 if (trace)
debfddc0
SL
83 tpacket("sent", &to, stp, size + 4);
84 n = sendto(f, sbuf, size + 4, 0, (caddr_t)&to, sizeof (to));
de3b21e8 85 if (n != size + 4) {
61ad9979 86 perror("tftp: sendto");
fc945f1a
SL
87 aborted = 1;
88 goto done;
d3fc13cc 89 }
61ad9979 90 do {
fc945f1a 91again:
61ad9979
SL
92 alarm(rexmtval);
93 do {
94 fromlen = sizeof (from);
debfddc0 95 n = recvfrom(f, rbuf, sizeof (rbuf), 0,
61ad9979
SL
96 (caddr_t)&from, &fromlen);
97 } while (n <= 0);
d3fc13cc 98 alarm(0);
61ad9979
SL
99 if (n < 0) {
100 perror("tftp: recvfrom");
fc945f1a
SL
101 aborted = 1;
102 goto done;
103 }
104 if (to.sin_addr.s_addr != from.sin_addr.s_addr) {
debfddc0
SL
105 tpacket("discarded (wrong host)",
106 &from, rtp, n);
fc945f1a
SL
107 goto again;
108 }
109 if (to.sin_port = sin.sin_port)
110 to.sin_port = from.sin_port;
111 if (to.sin_port != from.sin_port) {
debfddc0
SL
112 tpacket("discarded (wrong port)",
113 &from, rtp, n);
fc945f1a 114 goto again;
61ad9979
SL
115 }
116 if (trace)
debfddc0 117 tpacket("received", &from, rtp, n);
61ad9979 118 /* should verify packet came from server */
debfddc0
SL
119 rtp->th_opcode = ntohs(rtp->th_opcode);
120 rtp->th_block = ntohs(rtp->th_block);
121 if (rtp->th_opcode == ERROR) {
122 printf("Error code %d: %s\n", rtp->th_code,
123 rtp->th_msg);
fc945f1a
SL
124 aborted = 1;
125 goto done;
61ad9979 126 }
debfddc0 127 } while (rtp->th_opcode != ACK && block != rtp->th_block);
d3fc13cc
SL
128 if (block > 0)
129 amount += size;
130 block++;
131 } while (size == SEGSIZE || block == 1);
fc945f1a 132 if (!aborted && amount > 0) {
d3fc13cc
SL
133 delta = time(0) - start;
134 printf("Sent %d bytes in %d seconds.\n", amount, delta);
135 }
fc945f1a
SL
136done:
137 (void) close(fd);
138 return (aborted);
d3fc13cc
SL
139}
140
141/*
142 * Receive a file.
143 */
144recvfile(fd, name)
145 int fd;
146 char *name;
147{
debfddc0
SL
148 register struct tftphdr *stp = (struct tftphdr *)sbuf;
149 register struct tftphdr *rtp = (struct tftphdr *)rbuf;
d3fc13cc 150 register int block = 1, n, size, amount = 0;
fc945f1a 151 struct sockaddr_in from, to;
d3fc13cc 152 time_t start = time(0), delta;
fc945f1a 153 int fromlen, firsttrip = 1, aborted = 0;
d3fc13cc 154
fc945f1a 155 to = sin;
61ad9979 156 signal(SIGALRM, timer);
d3fc13cc 157 do {
61ad9979
SL
158 if (firsttrip) {
159 size = makerequest(RRQ, name);
160 firsttrip = 0;
161 } else {
debfddc0
SL
162 stp->th_opcode = htons((u_short)ACK);
163 stp->th_block = htons((u_short)(block));
61ad9979
SL
164 size = 4;
165 block++;
166 }
d3fc13cc 167 timeout = 0;
61ad9979 168 (void) setjmp(timeoutbuf);
d3fc13cc 169 if (trace)
debfddc0
SL
170 tpacket("sent", &to, stp, size);
171 if (sendto(f, sbuf, size, 0, (caddr_t)&to,
fc945f1a 172 sizeof (to)) != size) {
d3fc13cc 173 alarm(0);
61ad9979 174 perror("tftp: sendto");
fc945f1a
SL
175 aborted = 1;
176 goto done;
d3fc13cc 177 }
61ad9979 178 do {
fc945f1a 179again:
61ad9979 180 alarm(rexmtval);
fc945f1a
SL
181 do {
182 fromlen = sizeof (from);
debfddc0 183 n = recvfrom(f, rbuf, sizeof (rbuf), 0,
61ad9979 184 (caddr_t)&from, &fromlen);
fc945f1a 185 } while (n <= 0);
61ad9979
SL
186 alarm(0);
187 if (n < 0) {
188 perror("tftp: recvfrom");
fc945f1a
SL
189 aborted = 1;
190 goto done;
191 }
192 if (to.sin_addr.s_addr != from.sin_addr.s_addr) {
debfddc0
SL
193 tpacket("discarded (wrong host)",
194 &from, rtp, n);
fc945f1a
SL
195 goto again;
196 }
197 if (to.sin_port = sin.sin_port)
198 to.sin_port = from.sin_port;
199 if (to.sin_port != from.sin_port) {
debfddc0
SL
200 tpacket("discarded (wrong port)",
201 &from, rtp, n);
fc945f1a 202 goto again;
61ad9979
SL
203 }
204 if (trace)
debfddc0
SL
205 tpacket("received", &from, rtp, n);
206 rtp->th_opcode = ntohs(rtp->th_opcode);
207 rtp->th_block = ntohs(rtp->th_block);
208 if (rtp->th_opcode == ERROR) {
209 printf("Error code %d: %s\n", rtp->th_code,
210 rtp->th_msg);
fc945f1a
SL
211 aborted = 1;
212 goto done;
61ad9979 213 }
debfddc0
SL
214 } while (rtp->th_opcode != DATA && rtp->th_block != block);
215 size = write(fd, rtp->th_data, n - 4);
d3fc13cc 216 if (size < 0) {
fc945f1a
SL
217 perror("tftp: write");
218 nak(&to, errno + 100);
219 aborted = 1;
220 goto done;
d3fc13cc
SL
221 }
222 amount += size;
223 } while (size == SEGSIZE);
fc945f1a 224done:
debfddc0
SL
225 stp->th_opcode = htons((u_short)ACK);
226 stp->th_block = htons((u_short)block);
227 (void) sendto(f, sbuf, 4, 0, &to, sizeof (to));
d3fc13cc 228 (void) close(fd);
fc945f1a 229 if (!aborted && amount > 0) {
d3fc13cc
SL
230 delta = time(0) - start;
231 printf("Received %d bytes in %d seconds.\n", amount, delta);
232 }
fc945f1a 233 return (aborted);
d3fc13cc
SL
234}
235
236makerequest(request, name)
237 int request;
238 char *name;
239{
debfddc0 240 register struct tftphdr *stp;
d3fc13cc
SL
241 int size;
242 register char *cp;
243
debfddc0
SL
244 stp = (struct tftphdr *)sbuf;
245 stp->th_opcode = htons((u_short)request);
246 strcpy(stp->th_stuff, name);
d3fc13cc 247 size = strlen(name);
debfddc0 248 cp = stp->th_stuff + strlen(name);
d3fc13cc
SL
249 *cp++ = '\0';
250 strcpy(cp, mode);
251 cp += sizeof ("netascii") - 1;
252 *cp++ = '\0';
debfddc0 253 return (cp - sbuf);
d3fc13cc
SL
254}
255
256struct errmsg {
257 int e_code;
258 char *e_msg;
259} errmsgs[] = {
260 { EUNDEF, "Undefined error code" },
261 { ENOTFOUND, "File not found" },
262 { EACCESS, "Access violation" },
263 { ENOSPACE, "Disk full or allocation exceeded" },
264 { EBADOP, "Illegal TFTP operation" },
265 { EBADID, "Unknown transfer ID" },
266 { EEXISTS, "File already exists" },
267 { ENOUSER, "No such user" },
268 { -1, 0 }
269};
270
271/*
272 * Send a nak packet (error message).
273 * Error code passed in is one of the
274 * standard TFTP codes, or a UNIX errno
275 * offset by 100.
276 */
fc945f1a
SL
277nak(to, error)
278 struct sockaddr_in *to;
d3fc13cc
SL
279 int error;
280{
debfddc0 281 register struct tftphdr *stp;
d3fc13cc
SL
282 int length;
283 register struct errmsg *pe;
284 extern char *sys_errlist[];
285
debfddc0
SL
286 stp = (struct tftphdr *)sbuf;
287 stp->th_opcode = htons((u_short)ERROR);
288 stp->th_code = htons((u_short)error);
d3fc13cc
SL
289 for (pe = errmsgs; pe->e_code >= 0; pe++)
290 if (pe->e_code == error)
291 break;
292 if (pe->e_code < 0)
293 pe->e_msg = sys_errlist[error - 100];
debfddc0 294 strcpy(stp->th_msg, pe->e_msg);
d3fc13cc
SL
295 length = strlen(pe->e_msg) + 4;
296 if (trace)
debfddc0
SL
297 tpacket("sent", to, stp, length);
298 if (sendto(f, sbuf, length, 0, to, sizeof (*to)) != length)
fc945f1a 299 perror("tftp: nak");
d3fc13cc
SL
300}
301
fc945f1a
SL
302tpacket(s, sin, tp, n)
303 struct sockaddr_in *sin;
d3fc13cc
SL
304 struct tftphdr *tp;
305 int n;
306{
307 static char *opcodes[] =
308 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
309 register char *cp, *file;
310 u_short op = ntohs(tp->th_opcode);
311 char *index();
312
fc945f1a
SL
313 printf("%s ", s);
314 if (sin) {
315 struct hostent *hp = gethostbyaddr(&sin->sin_addr,
316 sizeof (sin->sin_addr), AF_INET);
317
318 printf("%s.%d ",
319 hp == 0 ? inet_ntoa(sin->sin_addr) : hp->h_name,
320 ntohs(sin->sin_port));
321 }
d3fc13cc 322 if (op < RRQ || op > ERROR)
fc945f1a 323 printf("opcode=%x ", op);
d3fc13cc 324 else
fc945f1a 325 printf("%s ", opcodes[op]);
d3fc13cc
SL
326 switch (op) {
327
328 case RRQ:
329 case WRQ:
330 n -= 2;
331 file = cp = tp->th_stuff;
332 cp = index(cp, '\0');
333 printf("<file=%s, mode=%s>\n", file, cp + 1);
334 break;
335
336 case DATA:
337 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
338 break;
339
340 case ACK:
341 printf("<block=%d>\n", ntohs(tp->th_block));
342 break;
343
344 case ERROR:
345 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
346 break;
6e87e2a6
SL
347
348 default:
349 putchar('\n');
350 break;
d3fc13cc
SL
351 }
352}