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