1 /* 2 * Copyright (c) 1983 Regents of the University of California. 3 * All rights reserved. 4 * 5 * %sccs.include.redist.c% 6 */ 7 8 #ifndef lint 9 static char sccsid[] = "@(#)tftp.c 5.10 (Berkeley) 03/01/91"; 10 #endif /* not lint */ 11 12 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 13 14 /* 15 * TFTP User Program -- Protocol Machines 16 */ 17 #include <sys/types.h> 18 #include <sys/socket.h> 19 #include <sys/time.h> 20 21 #include <netinet/in.h> 22 23 #include <arpa/tftp.h> 24 25 #include <signal.h> 26 #include <stdio.h> 27 #include <errno.h> 28 #include <setjmp.h> 29 30 extern int errno; 31 32 extern struct sockaddr_in sin; /* filled in by main */ 33 extern int f; /* the opened socket */ 34 extern int trace; 35 extern int verbose; 36 extern int rexmtval; 37 extern int maxtimeout; 38 39 #define PKTSIZE SEGSIZE+4 40 char ackbuf[PKTSIZE]; 41 int timeout; 42 jmp_buf toplevel; 43 jmp_buf timeoutbuf; 44 45 void 46 timer() 47 { 48 timeout += rexmtval; 49 if (timeout >= maxtimeout) { 50 printf("Transfer timed out.\n"); 51 longjmp(toplevel, -1); 52 } 53 longjmp(timeoutbuf, 1); 54 } 55 56 /* 57 * Send the requested file. 58 */ 59 sendfile(fd, name, mode) 60 int fd; 61 char *name; 62 char *mode; 63 { 64 register struct tftphdr *ap; /* data and ack packets */ 65 struct tftphdr *r_init(), *dp; 66 register int block = 0, size, n; 67 register unsigned long amount = 0; 68 struct sockaddr_in from; 69 int fromlen; 70 int convert; /* true if doing nl->crlf conversion */ 71 FILE *file; 72 73 startclock(); /* start stat's clock */ 74 dp = r_init(); /* reset fillbuf/read-ahead code */ 75 ap = (struct tftphdr *)ackbuf; 76 file = fdopen(fd, "r"); 77 convert = !strcmp(mode, "netascii"); 78 79 signal(SIGALRM, timer); 80 do { 81 if (block == 0) 82 size = makerequest(WRQ, name, dp, mode) - 4; 83 else { 84 /* size = read(fd, dp->th_data, SEGSIZE); */ 85 size = readit(file, &dp, convert); 86 if (size < 0) { 87 nak(errno + 100); 88 break; 89 } 90 dp->th_opcode = htons((u_short)DATA); 91 dp->th_block = htons((u_short)block); 92 } 93 timeout = 0; 94 (void) setjmp(timeoutbuf); 95 send_data: 96 if (trace) 97 tpacket("sent", dp, size + 4); 98 n = sendto(f, dp, size + 4, 0, 99 (struct sockaddr *)&sin, sizeof (sin)); 100 if (n != size + 4) { 101 perror("tftp: sendto"); 102 goto abort; 103 } 104 read_ahead(file, convert); 105 for ( ; ; ) { 106 alarm(rexmtval); 107 do { 108 fromlen = sizeof (from); 109 n = recvfrom(f, ackbuf, sizeof (ackbuf), 0, 110 (struct sockaddr *)&from, &fromlen); 111 } while (n <= 0); 112 alarm(0); 113 if (n < 0) { 114 perror("tftp: recvfrom"); 115 goto abort; 116 } 117 sin.sin_port = from.sin_port; /* added */ 118 if (trace) 119 tpacket("received", ap, n); 120 /* should verify packet came from server */ 121 ap->th_opcode = ntohs(ap->th_opcode); 122 ap->th_block = ntohs(ap->th_block); 123 if (ap->th_opcode == ERROR) { 124 printf("Error code %d: %s\n", ap->th_code, 125 ap->th_msg); 126 goto abort; 127 } 128 if (ap->th_opcode == ACK) { 129 int j; 130 131 if (ap->th_block == block) { 132 break; 133 } 134 /* On an error, try to synchronize 135 * both sides. 136 */ 137 j = synchnet(f); 138 if (j && trace) { 139 printf("discarded %d packets\n", 140 j); 141 } 142 if (ap->th_block == (block-1)) { 143 goto send_data; 144 } 145 } 146 } 147 if (block > 0) 148 amount += size; 149 block++; 150 } while (size == SEGSIZE || block == 1); 151 abort: 152 fclose(file); 153 stopclock(); 154 if (amount > 0) 155 printstats("Sent", amount); 156 } 157 158 /* 159 * Receive a file. 160 */ 161 recvfile(fd, name, mode) 162 int fd; 163 char *name; 164 char *mode; 165 { 166 register struct tftphdr *ap; 167 struct tftphdr *dp, *w_init(); 168 register int block = 1, n, size; 169 unsigned long amount = 0; 170 struct sockaddr_in from; 171 int fromlen, firsttrip = 1; 172 FILE *file; 173 int convert; /* true if converting crlf -> lf */ 174 175 startclock(); 176 dp = w_init(); 177 ap = (struct tftphdr *)ackbuf; 178 file = fdopen(fd, "w"); 179 convert = !strcmp(mode, "netascii"); 180 181 signal(SIGALRM, timer); 182 do { 183 if (firsttrip) { 184 size = makerequest(RRQ, name, ap, mode); 185 firsttrip = 0; 186 } else { 187 ap->th_opcode = htons((u_short)ACK); 188 ap->th_block = htons((u_short)(block)); 189 size = 4; 190 block++; 191 } 192 timeout = 0; 193 (void) setjmp(timeoutbuf); 194 send_ack: 195 if (trace) 196 tpacket("sent", ap, size); 197 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&sin, 198 sizeof (sin)) != size) { 199 alarm(0); 200 perror("tftp: sendto"); 201 goto abort; 202 } 203 write_behind(file, convert); 204 for ( ; ; ) { 205 alarm(rexmtval); 206 do { 207 fromlen = sizeof (from); 208 n = recvfrom(f, dp, PKTSIZE, 0, 209 (struct sockaddr *)&from, &fromlen); 210 } while (n <= 0); 211 alarm(0); 212 if (n < 0) { 213 perror("tftp: recvfrom"); 214 goto abort; 215 } 216 sin.sin_port = from.sin_port; /* added */ 217 if (trace) 218 tpacket("received", dp, n); 219 /* should verify client address */ 220 dp->th_opcode = ntohs(dp->th_opcode); 221 dp->th_block = ntohs(dp->th_block); 222 if (dp->th_opcode == ERROR) { 223 printf("Error code %d: %s\n", dp->th_code, 224 dp->th_msg); 225 goto abort; 226 } 227 if (dp->th_opcode == DATA) { 228 int j; 229 230 if (dp->th_block == block) { 231 break; /* have next packet */ 232 } 233 /* On an error, try to synchronize 234 * both sides. 235 */ 236 j = synchnet(f); 237 if (j && trace) { 238 printf("discarded %d packets\n", j); 239 } 240 if (dp->th_block == (block-1)) { 241 goto send_ack; /* resend ack */ 242 } 243 } 244 } 245 /* size = write(fd, dp->th_data, n - 4); */ 246 size = writeit(file, &dp, n - 4, convert); 247 if (size < 0) { 248 nak(errno + 100); 249 break; 250 } 251 amount += size; 252 } while (size == SEGSIZE); 253 abort: /* ok to ack, since user */ 254 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 255 ap->th_block = htons((u_short)block); 256 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&sin, sizeof (sin)); 257 write_behind(file, convert); /* flush last buffer */ 258 fclose(file); 259 stopclock(); 260 if (amount > 0) 261 printstats("Received", amount); 262 } 263 264 makerequest(request, name, tp, mode) 265 int request; 266 char *name, *mode; 267 struct tftphdr *tp; 268 { 269 register char *cp; 270 271 tp->th_opcode = htons((u_short)request); 272 cp = tp->th_stuff; 273 strcpy(cp, name); 274 cp += strlen(name); 275 *cp++ = '\0'; 276 strcpy(cp, mode); 277 cp += strlen(mode); 278 *cp++ = '\0'; 279 return (cp - (char *)tp); 280 } 281 282 struct errmsg { 283 int e_code; 284 char *e_msg; 285 } errmsgs[] = { 286 { EUNDEF, "Undefined error code" }, 287 { ENOTFOUND, "File not found" }, 288 { EACCESS, "Access violation" }, 289 { ENOSPACE, "Disk full or allocation exceeded" }, 290 { EBADOP, "Illegal TFTP operation" }, 291 { EBADID, "Unknown transfer ID" }, 292 { EEXISTS, "File already exists" }, 293 { ENOUSER, "No such user" }, 294 { -1, 0 } 295 }; 296 297 /* 298 * Send a nak packet (error message). 299 * Error code passed in is one of the 300 * standard TFTP codes, or a UNIX errno 301 * offset by 100. 302 */ 303 nak(error) 304 int error; 305 { 306 register struct errmsg *pe; 307 register struct tftphdr *tp; 308 int length; 309 char *strerror(); 310 311 tp = (struct tftphdr *)ackbuf; 312 tp->th_opcode = htons((u_short)ERROR); 313 tp->th_code = htons((u_short)error); 314 for (pe = errmsgs; pe->e_code >= 0; pe++) 315 if (pe->e_code == error) 316 break; 317 if (pe->e_code < 0) { 318 pe->e_msg = strerror(error - 100); 319 tp->th_code = EUNDEF; 320 } 321 strcpy(tp->th_msg, pe->e_msg); 322 length = strlen(pe->e_msg) + 4; 323 if (trace) 324 tpacket("sent", tp, length); 325 if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&sin, 326 sizeof (sin)) != length) 327 perror("nak"); 328 } 329 330 tpacket(s, tp, n) 331 char *s; 332 struct tftphdr *tp; 333 int n; 334 { 335 static char *opcodes[] = 336 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 337 register char *cp, *file; 338 u_short op = ntohs(tp->th_opcode); 339 char *index(); 340 341 if (op < RRQ || op > ERROR) 342 printf("%s opcode=%x ", s, op); 343 else 344 printf("%s %s ", s, opcodes[op]); 345 switch (op) { 346 347 case RRQ: 348 case WRQ: 349 n -= 2; 350 file = cp = tp->th_stuff; 351 cp = index(cp, '\0'); 352 printf("<file=%s, mode=%s>\n", file, cp + 1); 353 break; 354 355 case DATA: 356 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 357 break; 358 359 case ACK: 360 printf("<block=%d>\n", ntohs(tp->th_block)); 361 break; 362 363 case ERROR: 364 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 365 break; 366 } 367 } 368 369 struct timeval tstart; 370 struct timeval tstop; 371 struct timezone zone; 372 373 startclock() { 374 gettimeofday(&tstart, &zone); 375 } 376 377 stopclock() { 378 gettimeofday(&tstop, &zone); 379 } 380 381 printstats(direction, amount) 382 char *direction; 383 unsigned long amount; 384 { 385 double delta; 386 /* compute delta in 1/10's second units */ 387 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 388 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 389 delta = delta/10.; /* back to seconds */ 390 printf("%s %d bytes in %.1f seconds", direction, amount, delta); 391 if (verbose) 392 printf(" [%.0f bits/sec]", (amount*8.)/delta); 393 putchar('\n'); 394 } 395 396