1*9245Ssam /* tftp.c 4.4 82/11/15 */ 27770Ssam 37770Ssam /* 47770Ssam * TFTP User Program -- Protocol Machines 57770Ssam */ 67770Ssam #include <sys/types.h> 77770Ssam #include <sys/socket.h> 89220Ssam 99220Ssam #include <netinet/in.h> 109220Ssam 117770Ssam #include <signal.h> 127770Ssam #include <stdio.h> 137770Ssam #include <errno.h> 147770Ssam #include <setjmp.h> 159220Ssam 167770Ssam #include "tftp.h" 177770Ssam 187770Ssam extern int errno; 197770Ssam extern struct sockaddr_in sin; 207770Ssam extern char mode[]; 217770Ssam int f; 227770Ssam int trace; 237770Ssam int verbose; 247770Ssam int connected; 257770Ssam char buf[BUFSIZ]; 267770Ssam int timeout; 277770Ssam jmp_buf toplevel; 287770Ssam 297770Ssam timer() 307770Ssam { 317770Ssam timeout += TIMEOUT; 327770Ssam if (timeout >= MAXTIMEOUT) { 337770Ssam printf("Transfer timed out.\n"); 347770Ssam longjmp(toplevel, -1); 357770Ssam } 367770Ssam alarm(TIMEOUT); 377770Ssam } 387770Ssam 397770Ssam /* 407770Ssam * Send the requested file. 417770Ssam */ 427770Ssam sendfile(fd, name) 437770Ssam int fd; 447770Ssam char *name; 457770Ssam { 467770Ssam register struct tftphdr *tp = (struct tftphdr *)buf; 477770Ssam register int block = 0, size, n, amount = 0; 487770Ssam struct sockaddr_in from; 497770Ssam time_t start = time(0), delta; 509220Ssam int fromlen; 517770Ssam 527770Ssam size = makerequest(WRQ, name) - 4; 537778Ssam timeout = 0; 547770Ssam sigset(SIGALRM, timer); 557770Ssam do { 567770Ssam if (block != 0) { 577770Ssam size = read(fd, tp->th_data, SEGSIZE); 587770Ssam if (size < 0) { 597770Ssam nak(errno + 100); 607770Ssam break; 617770Ssam } 627770Ssam tp->th_opcode = htons((u_short)DATA); 637770Ssam tp->th_block = htons((u_short)block); 647770Ssam } 657770Ssam timeout = 0; 667770Ssam alarm(TIMEOUT); 677770Ssam rexmt: 687770Ssam if (trace) 697770Ssam tpacket("sent", tp, size + 4); 70*9245Ssam n = sendto(f, buf, size + 4, 0, (caddr_t)&sin, sizeof (sin)); 719220Ssam if (n != size + 4) { 727770Ssam perror("send"); 737770Ssam break; 747770Ssam } 757770Ssam again: 769220Ssam fromlen = sizeof (from); 77*9245Ssam n = recvfrom(f, buf, sizeof (buf), 0, (caddr_t)&from, &fromlen); 787770Ssam if (n <= 0) { 797770Ssam if (n == 0) 807770Ssam goto again; 817770Ssam if (errno == EINTR) 827770Ssam goto rexmt; 837770Ssam alarm(0); 847770Ssam perror("receive"); 857770Ssam break; 867770Ssam } 877770Ssam alarm(0); 887770Ssam if (trace) 897770Ssam tpacket("received", tp, n); 909220Ssam /* should verify packet came from server */ 917770Ssam #if vax || pdp11 927770Ssam tp->th_opcode = ntohs(tp->th_opcode); 937770Ssam tp->th_block = ntohs(tp->th_block); 947770Ssam #endif 957770Ssam if (tp->th_opcode == ERROR) { 967770Ssam printf("Error code %d: %s\n", tp->th_code, 977770Ssam tp->th_msg); 987770Ssam break; 997770Ssam } 1007770Ssam if (tp->th_opcode != ACK || block != tp->th_block) 1017770Ssam goto again; 1027770Ssam if (block > 0) 1037770Ssam amount += size; 1047770Ssam block++; 1057770Ssam } while (size == SEGSIZE || block == 1); 1067770Ssam alarm(0); 1077770Ssam (void) close(fd); 1087770Ssam if (amount > 0) { 1097770Ssam delta = time(0) - start; 1107770Ssam printf("Sent %d bytes in %d seconds.\n", amount, delta); 1117770Ssam } 1127770Ssam } 1137770Ssam 1147770Ssam /* 1157770Ssam * Receive a file. 1167770Ssam */ 1177770Ssam recvfile(fd, name) 1187770Ssam int fd; 1197770Ssam char *name; 1207770Ssam { 1217770Ssam register struct tftphdr *tp = (struct tftphdr *)buf; 1227770Ssam register int block = 1, n, size, amount = 0; 1237770Ssam struct sockaddr_in from; 1247770Ssam time_t start = time(0), delta; 1259220Ssam int fromlen; 1267770Ssam 1277770Ssam size = makerequest(RRQ, name); 1287778Ssam timeout = 0; 1297770Ssam sigset(SIGALRM, timer); 1307770Ssam alarm(TIMEOUT); 1317770Ssam goto rexmt; 1327770Ssam do { 1337770Ssam timeout = 0; 1347770Ssam alarm(TIMEOUT); 1357770Ssam tp->th_opcode = htons((u_short)ACK); 1367770Ssam tp->th_block = htons((u_short)(block)); 1377770Ssam size = 4; 1387770Ssam block++; 1397770Ssam rexmt: 1407770Ssam if (trace) 1417770Ssam tpacket("sent", tp, size); 142*9245Ssam if (sendto(f, buf, size, 0, (caddr_t)&sin, sizeof (sin)) != size) { 1437770Ssam perror("send"); 1447770Ssam break; 1457770Ssam } 1467770Ssam again: 147*9245Ssam n = recvfrom(f, buf, sizeof (buf), 0, (caddr_t)&from, &fromlen); 1487770Ssam if (n <= 0) { 1497770Ssam if (n == 0) 1507770Ssam goto again; 1517770Ssam if (errno == EINTR) 1527770Ssam goto rexmt; 1537770Ssam alarm(0); 1547770Ssam perror("receive"); 1557770Ssam break; 1567770Ssam } 1577770Ssam alarm(0); 1587770Ssam if (trace) 1597770Ssam tpacket("received", tp, n); 1609220Ssam /* should verify client address */ 1617770Ssam #if vax || pdp11 1627770Ssam tp->th_opcode = ntohs(tp->th_opcode); 1637770Ssam tp->th_block = ntohs(tp->th_block); 1647770Ssam #endif 1657770Ssam if (tp->th_opcode == ERROR) { 1667770Ssam printf("Error code %d: %s\n", tp->th_code, 1677770Ssam tp->th_msg); 1687770Ssam break; 1697770Ssam } 1707770Ssam if (tp->th_opcode != DATA || block != tp->th_block) 1717770Ssam goto again; 1727770Ssam size = write(fd, tp->th_data, n - 4); 1737770Ssam if (size < 0) { 1747770Ssam nak(errno + 100); 1757770Ssam break; 1767770Ssam } 1777770Ssam amount += size; 1787770Ssam } while (size == SEGSIZE); 1797770Ssam alarm(0); 1807770Ssam tp->th_opcode = htons((u_short)ACK); 1817770Ssam tp->th_block = htons((u_short)block); 182*9245Ssam (void) sendto(f, buf, 4, 0, &sin, sizeof (sin)); 1837770Ssam (void) close(fd); 1847770Ssam if (amount > 0) { 1857770Ssam delta = time(0) - start; 1867770Ssam printf("Received %d bytes in %d seconds.\n", amount, delta); 1877770Ssam } 1887770Ssam } 1897770Ssam 1907770Ssam makerequest(request, name) 1917770Ssam int request; 1927770Ssam char *name; 1937770Ssam { 1947770Ssam register struct tftphdr *tp; 1957770Ssam int size; 1967770Ssam register char *cp; 1977770Ssam 1987770Ssam tp = (struct tftphdr *)buf; 1997770Ssam tp->th_opcode = htons((u_short)request); 2007770Ssam strcpy(tp->th_stuff, name); 2017770Ssam size = strlen(name); 2027770Ssam cp = tp->th_stuff + strlen(name); 2037770Ssam *cp++ = '\0'; 2047770Ssam strcpy(cp, mode); 2057770Ssam cp += sizeof ("netascii") - 1; 2067770Ssam *cp++ = '\0'; 2077770Ssam return (cp - buf); 2087770Ssam } 2097770Ssam 2107770Ssam struct errmsg { 2117770Ssam int e_code; 2127770Ssam char *e_msg; 2137770Ssam } errmsgs[] = { 2147770Ssam { EUNDEF, "Undefined error code" }, 2157770Ssam { ENOTFOUND, "File not found" }, 2167770Ssam { EACCESS, "Access violation" }, 2177770Ssam { ENOSPACE, "Disk full or allocation exceeded" }, 2187770Ssam { EBADOP, "Illegal TFTP operation" }, 2197770Ssam { EBADID, "Unknown transfer ID" }, 2207770Ssam { EEXISTS, "File already exists" }, 2217770Ssam { ENOUSER, "No such user" }, 2227770Ssam { -1, 0 } 2237770Ssam }; 2247770Ssam 2257770Ssam /* 2267770Ssam * Send a nak packet (error message). 2277770Ssam * Error code passed in is one of the 2287770Ssam * standard TFTP codes, or a UNIX errno 2297770Ssam * offset by 100. 2307770Ssam */ 2317770Ssam nak(error) 2327770Ssam int error; 2337770Ssam { 2347770Ssam register struct tftphdr *tp; 2357770Ssam int length; 2367770Ssam register struct errmsg *pe; 2377770Ssam extern char *sys_errlist[]; 2387770Ssam 2397770Ssam tp = (struct tftphdr *)buf; 2407770Ssam tp->th_opcode = htons((u_short)ERROR); 2417770Ssam tp->th_code = htons((u_short)error); 2427770Ssam for (pe = errmsgs; pe->e_code >= 0; pe++) 2437770Ssam if (pe->e_code == error) 2447770Ssam break; 2457770Ssam if (pe->e_code < 0) 2467770Ssam pe->e_msg = sys_errlist[error - 100]; 2477770Ssam strcpy(tp->th_msg, pe->e_msg); 2487770Ssam length = strlen(pe->e_msg) + 4; 2497770Ssam if (trace) 2507770Ssam tpacket("sent", tp, length); 2517770Ssam if (send(f, &sin, buf, length) != length) 2527770Ssam perror("nak"); 2537770Ssam } 2547770Ssam 2557770Ssam tpacket(s, tp, n) 2567770Ssam struct tftphdr *tp; 2577770Ssam int n; 2587770Ssam { 2597770Ssam static char *opcodes[] = 2607770Ssam { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 2617770Ssam register char *cp, *file; 2627770Ssam u_short op = ntohs(tp->th_opcode); 2637770Ssam char *index(); 2647770Ssam 2657770Ssam if (op < RRQ || op > ERROR) 2667770Ssam printf("%s opcode=%x ", s, op); 2677770Ssam else 2687770Ssam printf("%s %s ", s, opcodes[op]); 2697770Ssam switch (op) { 2707770Ssam 2717770Ssam case RRQ: 2727770Ssam case WRQ: 2737770Ssam n -= 2; 2747770Ssam file = cp = tp->th_stuff; 2757770Ssam cp = index(cp, '\0'); 2767770Ssam printf("<file=%s, mode=%s>\n", file, cp + 1); 2777770Ssam break; 2787770Ssam 2797770Ssam case DATA: 2807770Ssam printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 2817770Ssam break; 2827770Ssam 2837770Ssam case ACK: 2847770Ssam printf("<block=%d>\n", ntohs(tp->th_block)); 2857770Ssam break; 2867770Ssam 2877770Ssam case ERROR: 2887770Ssam printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 2897770Ssam break; 2907770Ssam } 2917770Ssam } 292