1*7770Ssam /* tftp.c 4.1 82/08/16 */ 2*7770Ssam 3*7770Ssam /* 4*7770Ssam * TFTP User Program -- Protocol Machines 5*7770Ssam */ 6*7770Ssam #include <sys/types.h> 7*7770Ssam #include <net/in.h> 8*7770Ssam #include <sys/socket.h> 9*7770Ssam #include <signal.h> 10*7770Ssam #include <stdio.h> 11*7770Ssam #include <errno.h> 12*7770Ssam #include <setjmp.h> 13*7770Ssam #include "tftp.h" 14*7770Ssam 15*7770Ssam extern int errno; 16*7770Ssam extern struct sockaddr_in sin; 17*7770Ssam extern char mode[]; 18*7770Ssam int f; 19*7770Ssam int trace; 20*7770Ssam int verbose; 21*7770Ssam int connected; 22*7770Ssam char buf[BUFSIZ]; 23*7770Ssam int timeout; 24*7770Ssam jmp_buf toplevel; 25*7770Ssam 26*7770Ssam timer() 27*7770Ssam { 28*7770Ssam timeout += TIMEOUT; 29*7770Ssam if (timeout >= MAXTIMEOUT) { 30*7770Ssam printf("Transfer timed out.\n"); 31*7770Ssam longjmp(toplevel, -1); 32*7770Ssam } 33*7770Ssam alarm(TIMEOUT); 34*7770Ssam } 35*7770Ssam 36*7770Ssam /* 37*7770Ssam * Send the requested file. 38*7770Ssam */ 39*7770Ssam sendfile(fd, name) 40*7770Ssam int fd; 41*7770Ssam char *name; 42*7770Ssam { 43*7770Ssam register struct tftphdr *tp = (struct tftphdr *)buf; 44*7770Ssam register int block = 0, size, n, amount = 0; 45*7770Ssam struct sockaddr_in from; 46*7770Ssam time_t start = time(0), delta; 47*7770Ssam 48*7770Ssam size = makerequest(WRQ, name) - 4; 49*7770Ssam sigset(SIGALRM, timer); 50*7770Ssam do { 51*7770Ssam if (block != 0) { 52*7770Ssam size = read(fd, tp->th_data, SEGSIZE); 53*7770Ssam if (size < 0) { 54*7770Ssam nak(errno + 100); 55*7770Ssam break; 56*7770Ssam } 57*7770Ssam tp->th_opcode = htons((u_short)DATA); 58*7770Ssam tp->th_block = htons((u_short)block); 59*7770Ssam } 60*7770Ssam timeout = 0; 61*7770Ssam alarm(TIMEOUT); 62*7770Ssam rexmt: 63*7770Ssam if (trace) 64*7770Ssam tpacket("sent", tp, size + 4); 65*7770Ssam if (send(f, &sin, buf, size + 4) != size + 4) { 66*7770Ssam perror("send"); 67*7770Ssam break; 68*7770Ssam } 69*7770Ssam again: 70*7770Ssam n = receive(f, &from, buf, sizeof (buf)); 71*7770Ssam if (n <= 0) { 72*7770Ssam if (n == 0) 73*7770Ssam goto again; 74*7770Ssam if (errno == EINTR) 75*7770Ssam goto rexmt; 76*7770Ssam alarm(0); 77*7770Ssam perror("receive"); 78*7770Ssam break; 79*7770Ssam } 80*7770Ssam alarm(0); 81*7770Ssam if (trace) 82*7770Ssam tpacket("received", tp, n); 83*7770Ssam #if vax || pdp11 84*7770Ssam tp->th_opcode = ntohs(tp->th_opcode); 85*7770Ssam tp->th_block = ntohs(tp->th_block); 86*7770Ssam #endif 87*7770Ssam if (tp->th_opcode == ERROR) { 88*7770Ssam printf("Error code %d: %s\n", tp->th_code, 89*7770Ssam tp->th_msg); 90*7770Ssam break; 91*7770Ssam } 92*7770Ssam if (tp->th_opcode != ACK || block != tp->th_block) 93*7770Ssam goto again; 94*7770Ssam if (block > 0) 95*7770Ssam amount += size; 96*7770Ssam block++; 97*7770Ssam } while (size == SEGSIZE || block == 1); 98*7770Ssam alarm(0); 99*7770Ssam (void) close(fd); 100*7770Ssam if (amount > 0) { 101*7770Ssam delta = time(0) - start; 102*7770Ssam printf("Sent %d bytes in %d seconds.\n", amount, delta); 103*7770Ssam } 104*7770Ssam } 105*7770Ssam 106*7770Ssam /* 107*7770Ssam * Receive a file. 108*7770Ssam */ 109*7770Ssam recvfile(fd, name) 110*7770Ssam int fd; 111*7770Ssam char *name; 112*7770Ssam { 113*7770Ssam register struct tftphdr *tp = (struct tftphdr *)buf; 114*7770Ssam register int block = 1, n, size, amount = 0; 115*7770Ssam struct sockaddr_in from; 116*7770Ssam time_t start = time(0), delta; 117*7770Ssam 118*7770Ssam size = makerequest(RRQ, name); 119*7770Ssam sigset(SIGALRM, timer); 120*7770Ssam alarm(TIMEOUT); 121*7770Ssam goto rexmt; 122*7770Ssam do { 123*7770Ssam timeout = 0; 124*7770Ssam alarm(TIMEOUT); 125*7770Ssam tp->th_opcode = htons((u_short)ACK); 126*7770Ssam tp->th_block = htons((u_short)(block)); 127*7770Ssam size = 4; 128*7770Ssam block++; 129*7770Ssam rexmt: 130*7770Ssam if (trace) 131*7770Ssam tpacket("sent", tp, size); 132*7770Ssam if (send(f, &sin, buf, size) != size) { 133*7770Ssam perror("send"); 134*7770Ssam break; 135*7770Ssam } 136*7770Ssam again: 137*7770Ssam n = receive(f, &from, buf, sizeof (buf)); 138*7770Ssam if (n <= 0) { 139*7770Ssam if (n == 0) 140*7770Ssam goto again; 141*7770Ssam if (errno == EINTR) 142*7770Ssam goto rexmt; 143*7770Ssam alarm(0); 144*7770Ssam perror("receive"); 145*7770Ssam break; 146*7770Ssam } 147*7770Ssam alarm(0); 148*7770Ssam if (trace) 149*7770Ssam tpacket("received", tp, n); 150*7770Ssam #if vax || pdp11 151*7770Ssam tp->th_opcode = ntohs(tp->th_opcode); 152*7770Ssam tp->th_block = ntohs(tp->th_block); 153*7770Ssam #endif 154*7770Ssam if (tp->th_opcode == ERROR) { 155*7770Ssam printf("Error code %d: %s\n", tp->th_code, 156*7770Ssam tp->th_msg); 157*7770Ssam break; 158*7770Ssam } 159*7770Ssam if (tp->th_opcode != DATA || block != tp->th_block) 160*7770Ssam goto again; 161*7770Ssam size = write(fd, tp->th_data, n - 4); 162*7770Ssam if (size < 0) { 163*7770Ssam nak(errno + 100); 164*7770Ssam break; 165*7770Ssam } 166*7770Ssam amount += size; 167*7770Ssam } while (size == SEGSIZE); 168*7770Ssam alarm(0); 169*7770Ssam tp->th_opcode = htons((u_short)ACK); 170*7770Ssam tp->th_block = htons((u_short)block); 171*7770Ssam (void) send(f, &sin, buf, 4); 172*7770Ssam (void) close(fd); 173*7770Ssam if (amount > 0) { 174*7770Ssam delta = time(0) - start; 175*7770Ssam printf("Received %d bytes in %d seconds.\n", amount, delta); 176*7770Ssam } 177*7770Ssam } 178*7770Ssam 179*7770Ssam makerequest(request, name) 180*7770Ssam int request; 181*7770Ssam char *name; 182*7770Ssam { 183*7770Ssam register struct tftphdr *tp; 184*7770Ssam int size; 185*7770Ssam register char *cp; 186*7770Ssam 187*7770Ssam tp = (struct tftphdr *)buf; 188*7770Ssam tp->th_opcode = htons((u_short)request); 189*7770Ssam strcpy(tp->th_stuff, name); 190*7770Ssam size = strlen(name); 191*7770Ssam cp = tp->th_stuff + strlen(name); 192*7770Ssam *cp++ = '\0'; 193*7770Ssam strcpy(cp, mode); 194*7770Ssam cp += sizeof ("netascii") - 1; 195*7770Ssam *cp++ = '\0'; 196*7770Ssam return (cp - buf); 197*7770Ssam } 198*7770Ssam 199*7770Ssam struct errmsg { 200*7770Ssam int e_code; 201*7770Ssam char *e_msg; 202*7770Ssam } errmsgs[] = { 203*7770Ssam { EUNDEF, "Undefined error code" }, 204*7770Ssam { ENOTFOUND, "File not found" }, 205*7770Ssam { EACCESS, "Access violation" }, 206*7770Ssam { ENOSPACE, "Disk full or allocation exceeded" }, 207*7770Ssam { EBADOP, "Illegal TFTP operation" }, 208*7770Ssam { EBADID, "Unknown transfer ID" }, 209*7770Ssam { EEXISTS, "File already exists" }, 210*7770Ssam { ENOUSER, "No such user" }, 211*7770Ssam { -1, 0 } 212*7770Ssam }; 213*7770Ssam 214*7770Ssam /* 215*7770Ssam * Send a nak packet (error message). 216*7770Ssam * Error code passed in is one of the 217*7770Ssam * standard TFTP codes, or a UNIX errno 218*7770Ssam * offset by 100. 219*7770Ssam */ 220*7770Ssam nak(error) 221*7770Ssam int error; 222*7770Ssam { 223*7770Ssam register struct tftphdr *tp; 224*7770Ssam int length; 225*7770Ssam register struct errmsg *pe; 226*7770Ssam extern char *sys_errlist[]; 227*7770Ssam 228*7770Ssam tp = (struct tftphdr *)buf; 229*7770Ssam tp->th_opcode = htons((u_short)ERROR); 230*7770Ssam tp->th_code = htons((u_short)error); 231*7770Ssam for (pe = errmsgs; pe->e_code >= 0; pe++) 232*7770Ssam if (pe->e_code == error) 233*7770Ssam break; 234*7770Ssam if (pe->e_code < 0) 235*7770Ssam pe->e_msg = sys_errlist[error - 100]; 236*7770Ssam strcpy(tp->th_msg, pe->e_msg); 237*7770Ssam length = strlen(pe->e_msg) + 4; 238*7770Ssam if (trace) 239*7770Ssam tpacket("sent", tp, length); 240*7770Ssam if (send(f, &sin, buf, length) != length) 241*7770Ssam perror("nak"); 242*7770Ssam } 243*7770Ssam 244*7770Ssam tpacket(s, tp, n) 245*7770Ssam struct tftphdr *tp; 246*7770Ssam int n; 247*7770Ssam { 248*7770Ssam static char *opcodes[] = 249*7770Ssam { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 250*7770Ssam register char *cp, *file; 251*7770Ssam u_short op = ntohs(tp->th_opcode); 252*7770Ssam char *index(); 253*7770Ssam 254*7770Ssam if (op < RRQ || op > ERROR) 255*7770Ssam printf("%s opcode=%x ", s, op); 256*7770Ssam else 257*7770Ssam printf("%s %s ", s, opcodes[op]); 258*7770Ssam switch (op) { 259*7770Ssam 260*7770Ssam case RRQ: 261*7770Ssam case WRQ: 262*7770Ssam n -= 2; 263*7770Ssam file = cp = tp->th_stuff; 264*7770Ssam cp = index(cp, '\0'); 265*7770Ssam printf("<file=%s, mode=%s>\n", file, cp + 1); 266*7770Ssam break; 267*7770Ssam 268*7770Ssam case DATA: 269*7770Ssam printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 270*7770Ssam break; 271*7770Ssam 272*7770Ssam case ACK: 273*7770Ssam printf("<block=%d>\n", ntohs(tp->th_block)); 274*7770Ssam break; 275*7770Ssam 276*7770Ssam case ERROR: 277*7770Ssam printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 278*7770Ssam break; 279*7770Ssam } 280*7770Ssam } 281