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