Commit | Line | Data |
---|---|---|
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 | ||
18 | extern int errno; | |
19 | extern struct sockaddr_in sin; | |
20 | extern char mode[]; | |
21 | int f; | |
22 | int trace; | |
23 | int verbose; | |
24 | int connected; | |
25 | char buf[BUFSIZ]; | |
26 | int timeout; | |
27 | jmp_buf toplevel; | |
28 | ||
29 | timer() | |
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 | */ | |
42 | sendfile(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); | |
67 | rexmt: | |
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 | } | |
75 | again: | |
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 | */ | |
117 | recvfile(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++; | |
139 | rexmt: | |
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 | } | |
146 | again: | |
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 | ||
190 | makerequest(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 | ||
210 | struct 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 | */ | |
231 | nak(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 | ||
255 | tpacket(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 | } |