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