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