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: }