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