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