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