|
|
1.1 root 1: /*
2: * Copyright (c) 1985 Regents of the University of California.
3: * All rights reserved. The Berkeley software License Agreement
4: * specifies the terms and conditions for redistribution.
5: */
6:
7: #ifndef lint
8: static char sccsid[] = "@(#)tftp.c 5.5 (Berkeley) 2/7/86";
9: #endif not lint
10:
11: /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */
12:
13: /*
14: * TFTP User Program -- Protocol Machines
15: */
16: #include <sys/types.h>
17: #include <sys/socket.h>
18: #include <sys/time.h>
19:
20: #include <netinet/in.h>
21:
22: #include <arpa/tftp.h>
23:
24: #include <signal.h>
25: #include <stdio.h>
26: #include <errno.h>
27: #include <setjmp.h>
28:
29: extern int errno;
30:
31: extern struct sockaddr_in sin; /* filled in by main */
32: extern int f; /* the opened socket */
33: extern int trace;
34: extern int verbose;
35: extern int rexmtval;
36: extern int maxtimeout;
37:
38: #define PKTSIZE SEGSIZE+4
39: char ackbuf[PKTSIZE];
40: int timeout;
41: jmp_buf toplevel;
42: jmp_buf timeoutbuf;
43:
44: timer()
45: {
46:
47: timeout += rexmtval;
48: if (timeout >= maxtimeout) {
49: printf("Transfer timed out.\n");
50: longjmp(toplevel, -1);
51: }
52: longjmp(timeoutbuf, 1);
53: }
54:
55: /*
56: * Send the requested file.
57: */
58: sendfile(fd, name, mode)
59: int fd;
60: char *name;
61: char *mode;
62: {
63: register struct tftphdr *ap; /* data and ack packets */
64: struct tftphdr *r_init(), *dp;
65: register int block = 0, size, n;
66: register unsigned long amount = 0;
67: struct sockaddr_in from;
68: int fromlen;
69: int convert; /* true if doing nl->crlf conversion */
70: FILE *file;
71:
72: startclock(); /* start stat's clock */
73: dp = r_init(); /* reset fillbuf/read-ahead code */
74: ap = (struct tftphdr *)ackbuf;
75: file = fdopen(fd, "r");
76: convert = !strcmp(mode, "netascii");
77:
78: signal(SIGALRM, timer);
79: do {
80: if (block == 0)
81: size = makerequest(WRQ, name, dp, mode) - 4;
82: else {
83: /* size = read(fd, dp->th_data, SEGSIZE); */
84: size = readit(file, &dp, convert);
85: if (size < 0) {
86: nak(errno + 100);
87: break;
88: }
89: dp->th_opcode = htons((u_short)DATA);
90: dp->th_block = htons((u_short)block);
91: }
92: timeout = 0;
93: (void) setjmp(timeoutbuf);
94: send_data:
95: if (trace)
96: tpacket("sent", dp, size + 4);
97: n = sendto(f, dp, size + 4, 0, (caddr_t)&sin, sizeof (sin));
98: if (n != size + 4) {
99: perror("tftp: sendto");
100: goto abort;
101: }
102: read_ahead(file, convert);
103: for ( ; ; ) {
104: alarm(rexmtval);
105: do {
106: fromlen = sizeof (from);
107: n = recvfrom(f, ackbuf, sizeof (ackbuf), 0,
108: (caddr_t)&from, &fromlen);
109: } while (n <= 0);
110: alarm(0);
111: if (n < 0) {
112: perror("tftp: recvfrom");
113: goto abort;
114: }
115: sin.sin_port = from.sin_port; /* added */
116: if (trace)
117: tpacket("received", ap, n);
118: /* should verify packet came from server */
119: ap->th_opcode = ntohs(ap->th_opcode);
120: ap->th_block = ntohs(ap->th_block);
121: if (ap->th_opcode == ERROR) {
122: printf("Error code %d: %s\n", ap->th_code,
123: ap->th_msg);
124: goto abort;
125: }
126: if (ap->th_opcode == ACK) {
127: int j;
128:
129: if (ap->th_block == block) {
130: break;
131: }
132: /* On an error, try to synchronize
133: * both sides.
134: */
135: j = synchnet(f);
136: if (j && trace) {
137: printf("discarded %d packets\n",
138: j);
139: }
140: if (ap->th_block == (block-1)) {
141: goto send_data;
142: }
143: }
144: }
145: if (block > 0)
146: amount += size;
147: block++;
148: } while (size == SEGSIZE || block == 1);
149: abort:
150: fclose(file);
151: stopclock();
152: if (amount > 0)
153: printstats("Sent", amount);
154: }
155:
156: /*
157: * Receive a file.
158: */
159: recvfile(fd, name, mode)
160: int fd;
161: char *name;
162: char *mode;
163: {
164: register struct tftphdr *ap;
165: struct tftphdr *dp, *w_init();
166: register int block = 1, n, size;
167: unsigned long amount = 0;
168: struct sockaddr_in from;
169: int fromlen, firsttrip = 1;
170: FILE *file;
171: int convert; /* true if converting crlf -> lf */
172:
173: startclock();
174: dp = w_init();
175: ap = (struct tftphdr *)ackbuf;
176: file = fdopen(fd, "w");
177: convert = !strcmp(mode, "netascii");
178:
179: signal(SIGALRM, timer);
180: do {
181: if (firsttrip) {
182: size = makerequest(RRQ, name, ap, mode);
183: firsttrip = 0;
184: } else {
185: ap->th_opcode = htons((u_short)ACK);
186: ap->th_block = htons((u_short)(block));
187: size = 4;
188: block++;
189: }
190: timeout = 0;
191: (void) setjmp(timeoutbuf);
192: send_ack:
193: if (trace)
194: tpacket("sent", ap, size);
195: if (sendto(f, ackbuf, size, 0, (caddr_t)&sin,
196: sizeof (sin)) != size) {
197: alarm(0);
198: perror("tftp: sendto");
199: goto abort;
200: }
201: write_behind(file, convert);
202: for ( ; ; ) {
203: alarm(rexmtval);
204: do {
205: fromlen = sizeof (from);
206: n = recvfrom(f, dp, PKTSIZE, 0,
207: (caddr_t)&from, &fromlen);
208: } while (n <= 0);
209: alarm(0);
210: if (n < 0) {
211: perror("tftp: recvfrom");
212: goto abort;
213: }
214: sin.sin_port = from.sin_port; /* added */
215: if (trace)
216: tpacket("received", dp, n);
217: /* should verify client address */
218: dp->th_opcode = ntohs(dp->th_opcode);
219: dp->th_block = ntohs(dp->th_block);
220: if (dp->th_opcode == ERROR) {
221: printf("Error code %d: %s\n", dp->th_code,
222: dp->th_msg);
223: goto abort;
224: }
225: if (dp->th_opcode == DATA) {
226: int j;
227:
228: if (dp->th_block == block) {
229: break; /* have next packet */
230: }
231: /* On an error, try to synchronize
232: * both sides.
233: */
234: j = synchnet(f);
235: if (j && trace) {
236: printf("discarded %d packets\n", j);
237: }
238: if (dp->th_block == (block-1)) {
239: goto send_ack; /* resend ack */
240: }
241: }
242: }
243: /* size = write(fd, dp->th_data, n - 4); */
244: size = writeit(file, &dp, n - 4, convert);
245: if (size < 0) {
246: nak(errno + 100);
247: break;
248: }
249: amount += size;
250: } while (size == SEGSIZE);
251: abort: /* ok to ack, since user */
252: ap->th_opcode = htons((u_short)ACK); /* has seen err msg */
253: ap->th_block = htons((u_short)block);
254: (void) sendto(f, ackbuf, 4, 0, &sin, sizeof (sin));
255: write_behind(file, convert); /* flush last buffer */
256: fclose(file);
257: stopclock();
258: if (amount > 0)
259: printstats("Received", amount);
260: }
261:
262: makerequest(request, name, tp, mode)
263: int request;
264: char *name, *mode;
265: struct tftphdr *tp;
266: {
267: register char *cp;
268:
269: tp->th_opcode = htons((u_short)request);
270: cp = tp->th_stuff;
271: strcpy(cp, name);
272: cp += strlen(name);
273: *cp++ = '\0';
274: strcpy(cp, mode);
275: cp += strlen(mode);
276: *cp++ = '\0';
277: return (cp - (char *)tp);
278: }
279:
280: struct errmsg {
281: int e_code;
282: char *e_msg;
283: } errmsgs[] = {
284: { EUNDEF, "Undefined error code" },
285: { ENOTFOUND, "File not found" },
286: { EACCESS, "Access violation" },
287: { ENOSPACE, "Disk full or allocation exceeded" },
288: { EBADOP, "Illegal TFTP operation" },
289: { EBADID, "Unknown transfer ID" },
290: { EEXISTS, "File already exists" },
291: { ENOUSER, "No such user" },
292: { -1, 0 }
293: };
294:
295: /*
296: * Send a nak packet (error message).
297: * Error code passed in is one of the
298: * standard TFTP codes, or a UNIX errno
299: * offset by 100.
300: */
301: nak(error)
302: int error;
303: {
304: register struct tftphdr *tp;
305: int length;
306: register struct errmsg *pe;
307: extern char *sys_errlist[];
308:
309: tp = (struct tftphdr *)ackbuf;
310: tp->th_opcode = htons((u_short)ERROR);
311: tp->th_code = htons((u_short)error);
312: for (pe = errmsgs; pe->e_code >= 0; pe++)
313: if (pe->e_code == error)
314: break;
315: if (pe->e_code < 0) {
316: pe->e_msg = sys_errlist[error - 100];
317: tp->th_code = EUNDEF;
318: }
319: strcpy(tp->th_msg, pe->e_msg);
320: length = strlen(pe->e_msg) + 4;
321: if (trace)
322: tpacket("sent", tp, length);
323: if (sendto(f, ackbuf, length, 0, &sin, sizeof (sin)) != length)
324: perror("nak");
325: }
326:
327: tpacket(s, tp, n)
328: char *s;
329: struct tftphdr *tp;
330: int n;
331: {
332: static char *opcodes[] =
333: { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
334: register char *cp, *file;
335: u_short op = ntohs(tp->th_opcode);
336: char *index();
337:
338: if (op < RRQ || op > ERROR)
339: printf("%s opcode=%x ", s, op);
340: else
341: printf("%s %s ", s, opcodes[op]);
342: switch (op) {
343:
344: case RRQ:
345: case WRQ:
346: n -= 2;
347: file = cp = tp->th_stuff;
348: cp = index(cp, '\0');
349: printf("<file=%s, mode=%s>\n", file, cp + 1);
350: break;
351:
352: case DATA:
353: printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
354: break;
355:
356: case ACK:
357: printf("<block=%d>\n", ntohs(tp->th_block));
358: break;
359:
360: case ERROR:
361: printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
362: break;
363: }
364: }
365:
366: struct timeval tstart;
367: struct timeval tstop;
368: struct timezone zone;
369:
370: startclock() {
371: gettimeofday(&tstart, &zone);
372: }
373:
374: stopclock() {
375: gettimeofday(&tstop, &zone);
376: }
377:
378: printstats(direction, amount)
379: char *direction;
380: unsigned long amount;
381: {
382: double delta;
383: /* compute delta in 1/10's second units */
384: delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) -
385: ((tstart.tv_sec*10.)+(tstart.tv_usec/100000));
386: delta = delta/10.; /* back to seconds */
387: printf("%s %d bytes in %.1f seconds", direction, amount, delta);
388: if (verbose)
389: printf(" [%.0f bits/sec]", (amount*8.)/delta);
390: putchar('\n');
391: }
392:
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.