|
|
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.