|
|
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:
12: #include <netinet/in.h>
13:
14: #include <arpa/tftp.h>
15:
16: #include <signal.h>
17: #include <stdio.h>
18: #include <errno.h>
19: #include <setjmp.h>
20:
21:
22: /*----- to report system call error -----*/
23: extern int errno;
24: extern struct sockaddr_in sin;
25: extern char mode[];
26:
27: /*----- various options and their values -----*/
28: extern int f;
29: extern int trace;
30: extern int verbose;
31: extern int connected;
32: extern int rexmtval;
33: extern int maxtimeout;
34:
35: /*----- control messages -------*/
36: static char buf[BUFSIZ];
37:
38: /*----- communication connections ------*/
39: static struct sockaddr_in to;
40:
41: /*----- handling asynchronous events ----- */
42: static int timeout;
43: static jmp_buf timeoutbuf; /* timer expires */
44: static jmp_buf intrbuf; /* user abort */
45:
46: extern char *inet_ntoa(); /* unix library call */
47:
48: /*---------------------------------------------------
49: <<<<<<<<<<<<<<<<<<<<<<<<
50: <<<<<<< NOTES <<<<<<<<<< It does not pay to diff this version with
51: <<<<<<<<<<<<<<<<<<<<<<<< the original ucb version as this version
52: <<<<<<<<<<<<<<<<<<<<<<<< is nearly rewritten.
53:
54: Changes:
55:
56: . always report result even though transmitting 0 bytes
57: in recvfile() and sendfile(). Add local variable haserr
58: for this purpose.
59:
60: . add global variable "to".
61: at start of receiving or sending files, copy daemon address
62: "sin" to "to". send request to daemon throught "to".
63: when daemon child returns its address, set "to" = address
64: of daemon child. from then on, communicate with daemon child
65: (through "to").
66:
67: . connect to child daemon for performance and to ensure that
68: strayed messages are discarded by the system.
69:
70: . close the current file when timed out.
71:
72: . correct the connect() system call (call syntax was wrong)
73: in nak().
74:
75: . close the current file and socket when interrupted.
76: ----------------------------------------------------*/
77:
78: timer()
79: {
80: longjmp(timeoutbuf, 1);
81: }
82:
83: xmitintr()
84: {
85: alarm(0); /* turn off alarm */
86: longjmp(intrbuf, 1);
87: }
88:
89: /*-----------------------------------------
90: * Send the requested file.
91: -----------------------------------------*/
92: sendfile(currentfile, name)
93: FILE *currentfile;
94: char *name;
95: {
96: /*-------- data transfer parameters */
97: register struct tftphdr *tp = (struct tftphdr *)buf;
98: register int block = 0;
99: int xamount = 0; /* # bytes transmitted */
100: int xsize;
101: int famount = 0; /* # bytes read from file */
102: int fsize;
103:
104: int n;
105: int haserr = 0;
106:
107: /*-------- connection parameters */
108: struct sockaddr_in from;
109: int fromlen;
110:
111: /*-------- statistics parameters */
112: time_t start = time(0);
113: time_t delta;
114:
115: /*----- others */
116: int (*oldintr)(); /* interrupt handler */
117:
118: (void)signal(SIGALRM, timer);
119: oldintr = signal(SIGINT, xmitintr);
120: if (setjmp(intrbuf))
121: goto abort;
122:
123: do {
124: /*----- send request and ack -------*/
125: timeout = 0;
126: if (setjmp(timeoutbuf)) {
127: timeout += rexmtval;
128: if (timeout >= maxtimeout)
129: goto expire;
130: }
131:
132: if (trace)
133: tpacket("sent", tp, xsize + 4);
134:
135: if (block == 0) {
136: /* first trip */
137: xsize = makerequest(WRQ, name) - 4;
138: getsock();
139: to = sin;
140: n = sendto(f, buf, xsize + 4, 0, (caddr_t)&to,
141: sizeof (to));
142: }
143: else {
144: xsize = tftpread(currentfile, tp->th_data, SEGSIZE,
145: &fsize);
146: if (xsize < 0) {
147: perror("tftp:sendfile:read fails");
148: nak(errno + 100);
149: break;
150: }
151: tp->th_opcode = htons((u_short)DATA);
152: tp->th_block = htons((u_short)block);
153: n = send(f, buf, xsize+4, 0);
154: #ifdef DEBUG
155: fprintf(stderr,"send %d bytes, block %d\n",
156: xsize, block);
157: #endif
158: }
159:
160: if (n != xsize + 4) {
161: perror("tftp: sendto or send fails");
162: haserr++;
163: goto abort;
164: }
165:
166: /* get response and data */
167: do {
168: alarm(rexmtval);
169: do {
170: fromlen = sizeof (from);
171: n = recvfrom(f, buf, sizeof (buf), 0,
172: (caddr_t)&from, &fromlen);
173: } while (n <= 0);
174: alarm(0);
175: if (n < 0) {
176: perror("tftp: recvfrom fails");
177: haserr++;
178: goto abort;
179: }
180: #ifdef DEBUG
181: fprintf(stderr,"sendfile: recv from %s %d\n",
182: inet_ntoa(from.sin_addr), from.sin_port);
183: #endif
184: if (trace)
185: tpacket("received", tp, n, from.sin_port);
186:
187: /* use the address returned by daemon child */
188: if (block == 0) {
189: /* first trip */
190: if (connect(f, (char *)&from, sizeof(from))<0){
191: perror("tftp: connect fails");
192: haserr++;
193: goto abort;
194: }
195: to.sin_addr = from.sin_addr;
196: to.sin_port = from.sin_port;
197: }
198:
199: tp->th_opcode = ntohs(tp->th_opcode);
200: tp->th_block = ntohs(tp->th_block);
201: if (tp->th_opcode == ERROR) {
202: printf("Error code %d: %s\n", tp->th_code,
203: tp->th_msg);
204: haserr++;
205: goto abort;
206: }
207:
208: } while (tp->th_opcode != ACK ||
209: block != tp->th_block);
210:
211: if (block > 0) {
212: xamount += xsize;
213: famount += fsize;
214: }
215: block++;
216:
217: } while (xsize == SEGSIZE ||
218: block == 1);
219: abort:
220: done:
221: fclose(currentfile);
222: (void) close(f), f = -1;
223:
224: if (haserr == 0 ||
225: xamount >0) {
226: delta = time(0) - start;
227: printf("Read %d bytes and sent %d bytes in %d seconds.\n",
228: famount, xamount, delta);
229: }
230:
231: signal(SIGINT, oldintr);
232: oldintr = 0;
233: return;
234:
235: expire:
236: printf("Transfer timed out.\n");
237: goto abort;
238: }
239:
240:
241: /*---------------------------------------------
242: * Receive a file.
243: ----------------------------------------*/
244: recvfile(currentfile, name)
245: FILE *currentfile;
246: char *name;
247: {
248: /*----- file transfer bufs -------------*/
249: register struct tftphdr *tp = (struct tftphdr *)buf;
250: register int block = 1;
251: int xamount = 0;
252: int xsize;
253: int famount = 0;
254: int fsize;
255: int firsttrip = 1;
256:
257: int n,m;
258: int haserr = 0;
259: long segsize; /* for debugging purposes */
260:
261: /*----- connection --------*/
262: struct sockaddr_in from;
263: int fromlen;
264:
265: /*----- statistics --------*/
266: time_t start = time(0);
267: time_t delta;
268:
269: /*----- others -------*/
270: int (*oldintr)();
271:
272: signal(SIGALRM, timer);
273: oldintr = signal(SIGINT, xmitintr);
274: if (setjmp(intrbuf))
275: goto abort;
276:
277: /* file transfer */
278: do {
279:
280: /* send request/ acknowledgement */
281: timeout = 0;
282: if (setjmp(timeoutbuf)) {
283: timeout += rexmtval;
284: if (timeout >= maxtimeout)
285: goto expire;
286: }
287: if (trace)
288: tpacket("sent", tp, xsize);
289: if (firsttrip) {
290: xsize = makerequest(RRQ, name);
291: getsock();
292: to = sin;
293: n = sendto(f, buf, xsize, 0, (caddr_t)&to, sizeof(to));
294: } else {
295: tp->th_opcode = htons((u_short)ACK);
296: tp->th_block = htons((u_short)(block));
297: xsize = 4;
298: block++;
299: n = send(f, buf, xsize, 0);
300: }
301: if (n != xsize) {
302: alarm(0);
303: perror("tftp: sendto or send fails");
304: haserr++;
305: goto abort;
306: }
307:
308: /* get response and data */
309: do {
310: alarm(rexmtval);
311: do {
312: fromlen = sizeof(from);
313: n = recvfrom(f, buf, sizeof (buf), 0,
314: (caddr_t)&from, &fromlen);
315: } while (n <= 0);
316: alarm(0);
317: if (n < 0) {
318: perror("tftp: recvfrom");
319: haserr++;
320: goto abort;
321: }
322: #ifdef DEBUG
323: fprintf(stderr,"recvfile: recv from %s %d, n:%d\n",
324: inet_ntoa(from.sin_addr), from.sin_port,n);
325: #endif
326:
327: /* use the address returned by daemon child */
328: if (firsttrip) {
329: if (connect(f, (char *)&from, sizeof(from))<0){
330: perror("tftp: recvfile: connect fails");
331: haserr++;
332: goto abort;
333: }
334: to.sin_addr = from.sin_addr;
335: to.sin_port = from.sin_port;
336: firsttrip = 0;
337: }
338:
339: if (trace)
340: tpacket("received", tp, n,from.sin_port);
341:
342: tp->th_opcode = ntohs(tp->th_opcode);
343: tp->th_block = ntohs(tp->th_block);
344: if (tp->th_opcode == ERROR) {
345: fprintf(stderr,"Error code %d: %s\n",
346: tp->th_code, tp->th_msg);
347: haserr++;
348: goto abort;
349: }
350: } while (tp->th_opcode != DATA ||
351: block != tp->th_block);
352:
353: /* write to local file */
354: xsize = n -4;
355: n = tftpwrite(currentfile, tp->th_data, xsize, &fsize);
356: if (n < 0) {
357: perror("tftp:recvfile():write fails");
358: nak(errno + 100);
359: break;
360: }
361: xamount += xsize;
362: famount += fsize;
363: } while (xsize == SEGSIZE);
364: #ifdef DEBUG
365: fprintf(stderr,"Transfer complete: segsize %d, compare %d\n",
366: xsize, xsize==SEGSIZE);
367: #endif
368: abort:
369: done:
370: tp->th_opcode = htons((u_short)ACK);
371: tp->th_block = htons((u_short)block);
372: (void) send(f, buf, 4, 0);
373:
374: fclose(currentfile);
375: (void) close(f), f = -1;
376:
377: if (haserr == 0||
378: xamount > 0) {
379: delta = time(0) - start;
380: printf("Received %d bytes, wrote %d bytes in %d seconds.\n",
381: xamount, famount, delta);
382: }
383: signal(SIGINT, oldintr);
384: return;
385:
386: expire:
387: printf("Transfer timed out\n");
388: goto abort;
389: }
390:
391:
392: /*------------------------------------------------------------
393: makerequest
394: ----------------------------------------------------------*/
395: makerequest(request, name)
396: int request;
397: char *name;
398: {
399: register struct tftphdr *tp;
400: int size;
401: register char *cp;
402:
403: tp = (struct tftphdr *)buf;
404: tp->th_opcode = htons((u_short)request);
405: strcpy(tp->th_stuff, name);
406: size = strlen(name);
407: cp = tp->th_stuff + strlen(name);
408: *cp++ = '\0';
409: strcpy(cp, mode);
410: cp += sizeof ("netascii") - 1;
411: *cp++ = '\0';
412: return (cp - buf);
413: }
414:
415: struct errmsg {
416: int e_code;
417: char *e_msg;
418: } errmsgs[] = {
419: { EUNDEF, "Undefined error code" },
420: { ENOTFOUND, "File not found" },
421: { EACCESS, "Access violation" },
422: { ENOSPACE, "Disk full or allocation exceeded" },
423: { EBADOP, "Illegal TFTP operation" },
424: { EBADID, "Unknown transfer ID" },
425: { EEXISTS, "File already exists" },
426: { ENOUSER, "No such user" },
427: { -1, 0 }
428: };
429:
430: /*---------------------------------------------------
431: * Send a nak packet (error message).
432: * Error code passed in is one of the
433: * standard TFTP codes, or a UNIX errno
434: * offset by 100.
435: --------------------------------------------------*/
436: nak(error)
437: int error;
438: {
439: register struct tftphdr *tp;
440: int length;
441: register struct errmsg *pe;
442: extern char *sys_errlist[];
443:
444: tp = (struct tftphdr *)buf;
445: tp->th_opcode = htons((u_short)ERROR);
446: tp->th_code = htons((u_short)error);
447: for (pe = errmsgs; pe->e_code >= 0; pe++)
448: if (pe->e_code == error)
449: break;
450: if (pe->e_code < 0)
451: pe->e_msg = sys_errlist[error - 100];
452: strcpy(tp->th_msg, pe->e_msg);
453: length = strlen(pe->e_msg) + 4;
454: if (trace)
455: tpacket("sent", tp, length);
456: if (send(f, buf, length, 0) != length) {
457: perror("tftp:nak: send fails");
458: }
459: }
460:
461: /*------------------------------------------------------------
462: tpackets
463: ----------------------------------------------------------*/
464: tpacket(s, tp, n, dport)
465: struct tftphdr *tp;
466: int n, dport;
467: {
468: static char *opcodes[] =
469: { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
470: register char *cp, *file;
471: u_short op = ntohs(tp->th_opcode);
472: char *index();
473:
474: if (op < RRQ || op > ERROR)
475: printf("%s opcode=%x ", s, op);
476: else
477: printf("%s %s ", s, opcodes[op]);
478: switch (op) {
479:
480: case RRQ:
481: case WRQ:
482: n -= 2;
483: file = cp = tp->th_stuff;
484: cp = index(cp, '\0');
485: printf("<file=%s, mode=%s>\n", file, cp + 1);
486: break;
487:
488: case DATA:
489: printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
490: break;
491:
492: case ACK:
493: printf("<block=%d, from port=%d>\n",ntohs(tp->th_block),dport);
494: break;
495:
496: case ERROR:
497: printf("<code=%d, msglen=%ld, msg=%s>\n",
498: ntohs(tp->th_code),n, tp->th_msg);
499: break;
500: }
501: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.