Changed the data types for the sdb class characters to be unsigned
[unix-history] / usr / src / usr.bin / tftp / tftp.c
CommitLineData
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
15extern int errno;
16extern struct sockaddr_in sin;
17extern char mode[];
18int f;
19int trace;
20int verbose;
21int connected;
22char buf[BUFSIZ];
23int timeout;
24jmp_buf toplevel;
25
26timer()
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 */
39sendfile(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);
62rexmt:
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 }
69again:
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 */
109recvfile(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++;
129rexmt:
130 if (trace)
131 tpacket("sent", tp, size);
132 if (send(f, &sin, buf, size) != size) {
133 perror("send");
134 break;
135 }
136again:
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
179makerequest(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
199struct 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 */
220nak(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
244tpacket(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}