|
|
1.1 root 1: #ifndef lint
2: static char sccsid[] = "@(#)tftp.c 4.7 (Berkeley) 8/11/83";
3: #endif
4:
5: /*
6: * TFTP User Program -- Protocol Machines
7: */
8: #include <sys/types.h>
9: #include <sys/socket.h>
10:
11: #include <netinet/in.h>
12:
13: #include <arpa/tftp.h>
14:
15: #include <signal.h>
16: #include <stdio.h>
17: #include <errno.h>
18: #include <setjmp.h>
19:
20: extern int errno;
21: extern struct sockaddr_in sin;
22: extern char mode[];
23: int f;
24: int trace;
25: int verbose;
26: int connected;
27: char buf[BUFSIZ];
28: int rexmtval;
29: int maxtimeout;
30: int timeout;
31: jmp_buf toplevel;
32: jmp_buf timeoutbuf;
33:
34: timer()
35: {
36:
37: timeout += rexmtval;
38: if (timeout >= maxtimeout) {
39: printf("Transfer timed out.\n");
40: longjmp(toplevel, -1);
41: }
42: longjmp(timeoutbuf, 1);
43: }
44:
45: /*
46: * Send the requested file.
47: */
48: sendfile(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;
56: int fromlen;
57:
58: signal(SIGALRM, timer);
59: do {
60: if (block == 0)
61: size = makerequest(WRQ, name) - 4;
62: else {
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;
72: (void) setjmp(timeoutbuf);
73: if (trace)
74: tpacket("sent", tp, size + 4);
75: n = sendto(f, buf, size + 4, 0, (caddr_t)&sin, sizeof (sin));
76: if (n != size + 4) {
77: perror("tftp: sendto");
78: goto abort;
79: }
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);
87: alarm(0);
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);
103: if (block > 0)
104: amount += size;
105: block++;
106: } while (size == SEGSIZE || block == 1);
107: abort:
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: */
118: recvfile(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;
126: int fromlen, firsttrip = 1;
127:
128: signal(SIGALRM, timer);
129: do {
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: }
139: timeout = 0;
140: (void) setjmp(timeoutbuf);
141: if (trace)
142: tpacket("sent", tp, size);
143: if (sendto(f, buf, size, 0, (caddr_t)&sin,
144: sizeof (sin)) != size) {
145: alarm(0);
146: perror("tftp: sendto");
147: goto abort;
148: }
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);
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);
178: abort:
179: tp->th_opcode = htons((u_short)ACK);
180: tp->th_block = htons((u_short)block);
181: (void) sendto(f, buf, 4, 0, &sin, sizeof (sin));
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:
189: makerequest(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:
209: struct 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: */
230: nak(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:
254: tpacket(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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.