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