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