1 /* 2 * Copyright (c) 1983, 1993 3 * The Regents of the University of California. All rights reserved. 4 * 5 * Redistribution and use in source and binary forms, with or without 6 * modification, are permitted provided that the following conditions 7 * are met: 8 * 1. Redistributions of source code must retain the above copyright 9 * notice, this list of conditions and the following disclaimer. 10 * 2. Redistributions in binary form must reproduce the above copyright 11 * notice, this list of conditions and the following disclaimer in the 12 * documentation and/or other materials provided with the distribution. 13 * 3. All advertising materials mentioning features or use of this software 14 * must display the following acknowledgement: 15 * This product includes software developed by the University of 16 * California, Berkeley and its contributors. 17 * 4. Neither the name of the University nor the names of its contributors 18 * may be used to endorse or promote products derived from this software 19 * without specific prior written permission. 20 * 21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND 22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE 23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE 24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE 25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL 26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS 27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) 28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT 29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY 30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF 31 * SUCH DAMAGE. 32 */ 33 34 #if 0 35 #ifndef lint 36 static char sccsid[] = "@(#)tftp.c 8.1 (Berkeley) 6/6/93"; 37 #endif /* not lint */ 38 #endif 39 40 #include <sys/cdefs.h> 41 __FBSDID("$FreeBSD$"); 42 43 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 44 45 /* 46 * TFTP User Program -- Protocol Machines 47 */ 48 #include <sys/types.h> 49 #include <sys/socket.h> 50 #include <sys/time.h> 51 52 #include <netinet/in.h> 53 54 #include <arpa/inet.h> 55 #include <arpa/tftp.h> 56 57 #include <err.h> 58 #include <errno.h> 59 #include <setjmp.h> 60 #include <signal.h> 61 #include <stdio.h> 62 #include <string.h> 63 #include <unistd.h> 64 #include <netdb.h> 65 66 #include "extern.h" 67 #include "tftpsubs.h" 68 69 extern struct sockaddr_storage peeraddr; /* filled in by main */ 70 extern int f; /* the opened socket */ 71 extern int trace; 72 extern int verbose; 73 extern int rexmtval; 74 extern int maxtimeout; 75 extern volatile int txrx_error; 76 77 #define PKTSIZE SEGSIZE+4 78 char ackbuf[PKTSIZE]; 79 int timeout; 80 jmp_buf toplevel; 81 jmp_buf timeoutbuf; 82 83 static void nak(int, struct sockaddr *); 84 static int makerequest(int, const char *, struct tftphdr *, const char *); 85 static void printstats(const char *, unsigned long); 86 static void startclock(void); 87 static void stopclock(void); 88 static void timer(int); 89 static void tpacket(const char *, struct tftphdr *, int); 90 static int cmpport(struct sockaddr *, struct sockaddr *); 91 92 /* 93 * Send the requested file. 94 */ 95 void 96 xmitfile(fd, name, mode) 97 int fd; 98 char *name; 99 char *mode; 100 { 101 struct tftphdr *ap; /* data and ack packets */ 102 struct tftphdr *dp; 103 int n; 104 volatile unsigned short block; 105 volatile int size, convert; 106 volatile unsigned long amount; 107 struct sockaddr_storage from; 108 int fromlen; 109 FILE *file; 110 struct sockaddr_storage peer; 111 struct sockaddr_storage serv; /* valid server port number */ 112 113 startclock(); /* start stat's clock */ 114 dp = r_init(); /* reset fillbuf/read-ahead code */ 115 ap = (struct tftphdr *)ackbuf; 116 file = fdopen(fd, "r"); 117 convert = !strcmp(mode, "netascii"); 118 block = 0; 119 amount = 0; 120 memcpy(&peer, &peeraddr, peeraddr.ss_len); 121 memset(&serv, 0, sizeof(serv)); 122 123 signal(SIGALRM, timer); 124 do { 125 if (block == 0) 126 size = makerequest(WRQ, name, dp, mode) - 4; 127 else { 128 /* size = read(fd, dp->th_data, SEGSIZE); */ 129 size = readit(file, &dp, convert); 130 if (size < 0) { 131 nak(errno + 100, (struct sockaddr *)&peer); 132 break; 133 } 134 dp->th_opcode = htons((u_short)DATA); 135 dp->th_block = htons((u_short)block); 136 } 137 timeout = 0; 138 (void) setjmp(timeoutbuf); 139 send_data: 140 if (trace) 141 tpacket("sent", dp, size + 4); 142 n = sendto(f, dp, size + 4, 0, 143 (struct sockaddr *)&peer, peer.ss_len); 144 if (n != size + 4) { 145 warn("sendto"); 146 goto abort; 147 } 148 read_ahead(file, convert); 149 for ( ; ; ) { 150 alarm(rexmtval); 151 do { 152 fromlen = sizeof(from); 153 n = recvfrom(f, ackbuf, sizeof(ackbuf), 0, 154 (struct sockaddr *)&from, &fromlen); 155 } while (n <= 0); 156 alarm(0); 157 if (n < 0) { 158 warn("recvfrom"); 159 goto abort; 160 } 161 if (!serv.ss_family) 162 serv = from; 163 else if (!cmpport((struct sockaddr *)&serv, 164 (struct sockaddr *)&from)) { 165 warn("server port mismatch"); 166 goto abort; 167 } 168 peer = from; 169 if (trace) 170 tpacket("received", ap, n); 171 /* should verify packet came from server */ 172 ap->th_opcode = ntohs(ap->th_opcode); 173 ap->th_block = ntohs(ap->th_block); 174 if (ap->th_opcode == ERROR) { 175 printf("Error code %d: %s\n", ap->th_code, 176 ap->th_msg); 177 txrx_error = 1; 178 goto abort; 179 } 180 if (ap->th_opcode == ACK) { 181 int j; 182 183 if (ap->th_block == block) { 184 break; 185 } 186 /* On an error, try to synchronize 187 * both sides. 188 */ 189 j = synchnet(f); 190 if (j && trace) { 191 printf("discarded %d packets\n", 192 j); 193 } 194 if (ap->th_block == (block-1)) { 195 goto send_data; 196 } 197 } 198 } 199 if (block > 0) 200 amount += size; 201 block++; 202 } while (size == SEGSIZE || block == 1); 203 abort: 204 fclose(file); 205 stopclock(); 206 if (amount > 0) 207 printstats("Sent", amount); 208 } 209 210 /* 211 * Receive a file. 212 */ 213 void 214 recvfile(fd, name, mode) 215 int fd; 216 char *name; 217 char *mode; 218 { 219 struct tftphdr *ap; 220 struct tftphdr *dp; 221 int n; 222 volatile unsigned short block; 223 volatile int size, firsttrip; 224 volatile unsigned long amount; 225 struct sockaddr_storage from; 226 int fromlen; 227 FILE *file; 228 volatile int convert; /* true if converting crlf -> lf */ 229 struct sockaddr_storage peer; 230 struct sockaddr_storage serv; /* valid server port number */ 231 232 startclock(); 233 dp = w_init(); 234 ap = (struct tftphdr *)ackbuf; 235 file = fdopen(fd, "w"); 236 convert = !strcmp(mode, "netascii"); 237 block = 1; 238 firsttrip = 1; 239 amount = 0; 240 memcpy(&peer, &peeraddr, peeraddr.ss_len); 241 memset(&serv, 0, sizeof(serv)); 242 243 signal(SIGALRM, timer); 244 do { 245 if (firsttrip) { 246 size = makerequest(RRQ, name, ap, mode); 247 firsttrip = 0; 248 } else { 249 ap->th_opcode = htons((u_short)ACK); 250 ap->th_block = htons((u_short)(block)); 251 size = 4; 252 block++; 253 } 254 timeout = 0; 255 (void) setjmp(timeoutbuf); 256 send_ack: 257 if (trace) 258 tpacket("sent", ap, size); 259 if (sendto(f, ackbuf, size, 0, (struct sockaddr *)&peer, 260 peer.ss_len) != size) { 261 alarm(0); 262 warn("sendto"); 263 goto abort; 264 } 265 write_behind(file, convert); 266 for ( ; ; ) { 267 alarm(rexmtval); 268 do { 269 fromlen = sizeof(from); 270 n = recvfrom(f, dp, PKTSIZE, 0, 271 (struct sockaddr *)&from, &fromlen); 272 } while (n <= 0); 273 alarm(0); 274 if (n < 0) { 275 warn("recvfrom"); 276 goto abort; 277 } 278 if (!serv.ss_family) 279 serv = from; 280 else if (!cmpport((struct sockaddr *)&serv, 281 (struct sockaddr *)&from)) { 282 warn("server port mismatch"); 283 goto abort; 284 } 285 peer = from; 286 if (trace) 287 tpacket("received", dp, n); 288 /* should verify client address */ 289 dp->th_opcode = ntohs(dp->th_opcode); 290 dp->th_block = ntohs(dp->th_block); 291 if (dp->th_opcode == ERROR) { 292 printf("Error code %d: %s\n", dp->th_code, 293 dp->th_msg); 294 txrx_error = 1; 295 goto abort; 296 } 297 if (dp->th_opcode == DATA) { 298 int j; 299 300 if (dp->th_block == block) { 301 break; /* have next packet */ 302 } 303 /* On an error, try to synchronize 304 * both sides. 305 */ 306 j = synchnet(f); 307 if (j && trace) { 308 printf("discarded %d packets\n", j); 309 } 310 if (dp->th_block == (block-1)) { 311 goto send_ack; /* resend ack */ 312 } 313 } 314 } 315 /* size = write(fd, dp->th_data, n - 4); */ 316 size = writeit(file, &dp, n - 4, convert); 317 if (size < 0) { 318 nak(errno + 100, (struct sockaddr *)&peer); 319 break; 320 } 321 amount += size; 322 } while (size == SEGSIZE); 323 abort: /* ok to ack, since user */ 324 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 325 ap->th_block = htons((u_short)block); 326 (void) sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peer, 327 peer.ss_len); 328 write_behind(file, convert); /* flush last buffer */ 329 fclose(file); 330 stopclock(); 331 if (amount > 0) 332 printstats("Received", amount); 333 } 334 335 static int 336 makerequest(request, name, tp, mode) 337 int request; 338 const char *name; 339 struct tftphdr *tp; 340 const char *mode; 341 { 342 char *cp; 343 344 tp->th_opcode = htons((u_short)request); 345 cp = tp->th_stuff; 346 strcpy(cp, name); 347 cp += strlen(name); 348 *cp++ = '\0'; 349 strcpy(cp, mode); 350 cp += strlen(mode); 351 *cp++ = '\0'; 352 return (cp - (char *)tp); 353 } 354 355 struct errmsg { 356 int e_code; 357 const char *e_msg; 358 } errmsgs[] = { 359 { EUNDEF, "Undefined error code" }, 360 { ENOTFOUND, "File not found" }, 361 { EACCESS, "Access violation" }, 362 { ENOSPACE, "Disk full or allocation exceeded" }, 363 { EBADOP, "Illegal TFTP operation" }, 364 { EBADID, "Unknown transfer ID" }, 365 { EEXISTS, "File already exists" }, 366 { ENOUSER, "No such user" }, 367 { -1, 0 } 368 }; 369 370 /* 371 * Send a nak packet (error message). 372 * Error code passed in is one of the 373 * standard TFTP codes, or a UNIX errno 374 * offset by 100. 375 */ 376 static void 377 nak(error, peer) 378 int error; 379 struct sockaddr *peer; 380 { 381 struct errmsg *pe; 382 struct tftphdr *tp; 383 int length; 384 385 tp = (struct tftphdr *)ackbuf; 386 tp->th_opcode = htons((u_short)ERROR); 387 tp->th_code = htons((u_short)error); 388 for (pe = errmsgs; pe->e_code >= 0; pe++) 389 if (pe->e_code == error) 390 break; 391 if (pe->e_code < 0) { 392 pe->e_msg = strerror(error - 100); 393 tp->th_code = EUNDEF; 394 } 395 strcpy(tp->th_msg, pe->e_msg); 396 length = strlen(pe->e_msg) + 4; 397 if (trace) 398 tpacket("sent", tp, length); 399 if (sendto(f, ackbuf, length, 0, peer, peer->sa_len) != length) 400 warn("nak"); 401 } 402 403 static void 404 tpacket(s, tp, n) 405 const char *s; 406 struct tftphdr *tp; 407 int n; 408 { 409 static const char *opcodes[] = 410 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 411 char *cp, *file; 412 u_short op = ntohs(tp->th_opcode); 413 414 if (op < RRQ || op > ERROR) 415 printf("%s opcode=%x ", s, op); 416 else 417 printf("%s %s ", s, opcodes[op]); 418 switch (op) { 419 420 case RRQ: 421 case WRQ: 422 n -= 2; 423 file = cp = tp->th_stuff; 424 cp = index(cp, '\0'); 425 printf("<file=%s, mode=%s>\n", file, cp + 1); 426 break; 427 428 case DATA: 429 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 430 break; 431 432 case ACK: 433 printf("<block=%d>\n", ntohs(tp->th_block)); 434 break; 435 436 case ERROR: 437 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 438 break; 439 } 440 } 441 442 struct timeval tstart; 443 struct timeval tstop; 444 445 static void 446 startclock() 447 { 448 449 (void)gettimeofday(&tstart, NULL); 450 } 451 452 static void 453 stopclock() 454 { 455 456 (void)gettimeofday(&tstop, NULL); 457 } 458 459 static void 460 printstats(direction, amount) 461 const char *direction; 462 unsigned long amount; 463 { 464 double delta; 465 /* compute delta in 1/10's second units */ 466 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 467 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 468 delta = delta/10.; /* back to seconds */ 469 printf("%s %ld bytes in %.1f seconds", direction, amount, delta); 470 if (verbose) 471 printf(" [%.0f bits/sec]", (amount*8.)/delta); 472 putchar('\n'); 473 } 474 475 static void 476 timer(sig) 477 int sig __unused; 478 { 479 480 timeout += rexmtval; 481 if (timeout >= maxtimeout) { 482 printf("Transfer timed out.\n"); 483 longjmp(toplevel, -1); 484 } 485 txrx_error = 1; 486 longjmp(timeoutbuf, 1); 487 } 488 489 static int 490 cmpport(sa, sb) 491 struct sockaddr *sa; 492 struct sockaddr *sb; 493 { 494 char a[NI_MAXSERV], b[NI_MAXSERV]; 495 496 if (getnameinfo(sa, sa->sa_len, NULL, 0, a, sizeof(a), NI_NUMERICSERV)) 497 return 0; 498 if (getnameinfo(sb, sb->sa_len, NULL, 0, b, sizeof(b), NI_NUMERICSERV)) 499 return 0; 500 if (strcmp(a, b) != 0) 501 return 0; 502 503 return 1; 504 } 505