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