1 /* 2 * Copyright (c) 1985 Regents of the University of California. 3 * All rights reserved. The Berkeley software License Agreement 4 * specifies the terms and conditions for redistribution. 5 */ 6 7 #ifndef lint 8 static char sccsid[] = "@(#)tftp.c 5.3 (Berkeley) 02/07/86"; 9 #endif not lint 10 11 /* Many bug fixes are from Jim Guyton <guyton@rand-unix> */ 12 13 /* 14 * TFTP User Program -- Protocol Machines 15 */ 16 #include <sys/types.h> 17 #include <sys/socket.h> 18 #include <sys/ioctl.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 timer() 46 { 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 /* Now, we flush anything pending to be read */ 97 /* This is to try to keep in synch between the two sides */ 98 while (1) { 99 int i, j = 0; 100 char rbuf[PKTSIZE]; 101 102 (void) ioctl(f, FIONREAD, &i); 103 if (i) { 104 j++; 105 fromlen = sizeof from; 106 n = recvfrom(f, rbuf, sizeof (rbuf), 0, 107 (caddr_t)&from, &fromlen); 108 } else { 109 if (j && trace) { 110 printf("discarded %d packets\n", j); 111 } 112 break; 113 } 114 } 115 if (trace) 116 tpacket("sent", dp, size + 4); 117 n = sendto(f, dp, size + 4, 0, (caddr_t)&sin, sizeof (sin)); 118 if (n != size + 4) { 119 perror("tftp: sendto"); 120 goto abort; 121 } 122 read_ahead(file, convert); 123 for ( ; ; ) { 124 alarm(rexmtval); 125 do { 126 fromlen = sizeof (from); 127 n = recvfrom(f, ackbuf, sizeof (ackbuf), 0, 128 (caddr_t)&from, &fromlen); 129 } while (n <= 0); 130 alarm(0); 131 if (n < 0) { 132 perror("tftp: recvfrom"); 133 goto abort; 134 } 135 sin.sin_port = from.sin_port; /* added */ 136 if (trace) 137 tpacket("received", ap, n); 138 /* should verify packet came from server */ 139 ap->th_opcode = ntohs(ap->th_opcode); 140 ap->th_block = ntohs(ap->th_block); 141 if (ap->th_opcode == ERROR) { 142 printf("Error code %d: %s\n", ap->th_code, 143 ap->th_msg); 144 goto abort; 145 } 146 if (ap->th_opcode == ACK) { 147 if (ap->th_block == block) { 148 break; 149 } else if (ap->th_block == (block-1)) { 150 goto send_data; /* resend packet */ 151 } 152 } 153 } 154 if (block > 0) 155 amount += size; 156 block++; 157 } while (size == SEGSIZE || block == 1); 158 abort: 159 fclose(file); 160 stopclock(); 161 if (amount > 0) 162 printstats("Sent", amount); 163 } 164 165 /* 166 * Receive a file. 167 */ 168 recvfile(fd, name, mode) 169 int fd; 170 char *name; 171 char *mode; 172 { 173 register struct tftphdr *ap; 174 struct tftphdr *dp, *w_init(); 175 register int block = 1, n, size; 176 unsigned long amount = 0; 177 struct sockaddr_in from; 178 int fromlen, firsttrip = 1; 179 FILE *file; 180 int convert; /* true if converting crlf -> lf */ 181 182 startclock(); 183 dp = w_init(); 184 ap = (struct tftphdr *)ackbuf; 185 file = fdopen(fd, "w"); 186 convert = !strcmp(mode, "netascii"); 187 188 signal(SIGALRM, timer); 189 do { 190 if (firsttrip) { 191 size = makerequest(RRQ, name, ap, mode); 192 firsttrip = 0; 193 } else { 194 ap->th_opcode = htons((u_short)ACK); 195 ap->th_block = htons((u_short)(block)); 196 size = 4; 197 block++; 198 } 199 timeout = 0; 200 (void) setjmp(timeoutbuf); 201 send_ack: 202 /* Now, we flush anything pending to be read */ 203 /* This is to try to keep in synch between the two sides */ 204 while (1) { 205 int i, j = 0; 206 char rbuf[PKTSIZE]; 207 208 (void) ioctl(f, FIONREAD, &i); 209 if (i) { 210 j++; 211 fromlen = sizeof from; 212 n = recvfrom(f, rbuf, sizeof (rbuf), 0, 213 (caddr_t)&from, &fromlen); 214 } else { 215 if (j && trace) { 216 printf("discarded %d packets\n", j); 217 } 218 break; 219 } 220 } 221 if (trace) 222 tpacket("sent", ap, size); 223 if (sendto(f, ackbuf, size, 0, (caddr_t)&sin, 224 sizeof (sin)) != size) { 225 alarm(0); 226 perror("tftp: sendto"); 227 goto abort; 228 } 229 write_behind(file, convert); 230 for ( ; ; ) { 231 alarm(rexmtval); 232 do { 233 fromlen = sizeof (from); 234 n = recvfrom(f, dp, PKTSIZE, 0, 235 (caddr_t)&from, &fromlen); 236 } while (n <= 0); 237 alarm(0); 238 if (n < 0) { 239 perror("tftp: recvfrom"); 240 goto abort; 241 } 242 sin.sin_port = from.sin_port; /* added */ 243 if (trace) 244 tpacket("received", dp, n); 245 /* should verify client address */ 246 dp->th_opcode = ntohs(dp->th_opcode); 247 dp->th_block = ntohs(dp->th_block); 248 if (dp->th_opcode == ERROR) { 249 printf("Error code %d: %s\n", dp->th_code, 250 dp->th_msg); 251 goto abort; 252 } 253 if (dp->th_opcode == DATA) { 254 if (dp->th_block == block) 255 break; /* have next packet */ 256 if (dp->th_block == (block-1)) 257 goto send_ack; /* resend ack */ 258 } 259 } 260 /* size = write(fd, dp->th_data, n - 4); */ 261 size = writeit(file, &dp, n - 4, convert); 262 if (size < 0) { 263 nak(errno + 100); 264 break; 265 } 266 amount += size; 267 } while (size == SEGSIZE); 268 abort: /* ok to ack, since user */ 269 ap->th_opcode = htons((u_short)ACK); /* has seen err msg */ 270 ap->th_block = htons((u_short)block); 271 (void) sendto(f, ackbuf, 4, 0, &sin, sizeof (sin)); 272 write_behind(file, convert); /* flush last buffer */ 273 fclose(file); 274 stopclock(); 275 if (amount > 0) 276 printstats("Received", amount); 277 } 278 279 makerequest(request, name, tp, mode) 280 int request; 281 char *name, *mode; 282 struct tftphdr *tp; 283 { 284 register char *cp; 285 286 tp->th_opcode = htons((u_short)request); 287 cp = tp->th_stuff; 288 strcpy(cp, name); 289 cp += strlen(name); 290 *cp++ = '\0'; 291 strcpy(cp, mode); 292 cp += strlen(mode); 293 *cp++ = '\0'; 294 return (cp - (char *)tp); 295 } 296 297 struct errmsg { 298 int e_code; 299 char *e_msg; 300 } errmsgs[] = { 301 { EUNDEF, "Undefined error code" }, 302 { ENOTFOUND, "File not found" }, 303 { EACCESS, "Access violation" }, 304 { ENOSPACE, "Disk full or allocation exceeded" }, 305 { EBADOP, "Illegal TFTP operation" }, 306 { EBADID, "Unknown transfer ID" }, 307 { EEXISTS, "File already exists" }, 308 { ENOUSER, "No such user" }, 309 { -1, 0 } 310 }; 311 312 /* 313 * Send a nak packet (error message). 314 * Error code passed in is one of the 315 * standard TFTP codes, or a UNIX errno 316 * offset by 100. 317 */ 318 nak(error) 319 int error; 320 { 321 register struct tftphdr *tp; 322 int length; 323 register struct errmsg *pe; 324 extern char *sys_errlist[]; 325 326 tp = (struct tftphdr *)ackbuf; 327 tp->th_opcode = htons((u_short)ERROR); 328 tp->th_code = htons((u_short)error); 329 for (pe = errmsgs; pe->e_code >= 0; pe++) 330 if (pe->e_code == error) 331 break; 332 if (pe->e_code < 0) { 333 pe->e_msg = sys_errlist[error - 100]; 334 tp->th_code = EUNDEF; 335 } 336 strcpy(tp->th_msg, pe->e_msg); 337 length = strlen(pe->e_msg) + 4; 338 if (trace) 339 tpacket("sent", tp, length); 340 if (sendto(f, ackbuf, length, 0, &sin, sizeof (sin)) != length) 341 perror("nak"); 342 } 343 344 tpacket(s, tp, n) 345 struct tftphdr *tp; 346 int n; 347 { 348 static char *opcodes[] = 349 { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" }; 350 register char *cp, *file; 351 u_short op = ntohs(tp->th_opcode); 352 char *index(); 353 354 if (op < RRQ || op > ERROR) 355 printf("%s opcode=%x ", s, op); 356 else 357 printf("%s %s ", s, opcodes[op]); 358 switch (op) { 359 360 case RRQ: 361 case WRQ: 362 n -= 2; 363 file = cp = tp->th_stuff; 364 cp = index(cp, '\0'); 365 printf("<file=%s, mode=%s>\n", file, cp + 1); 366 break; 367 368 case DATA: 369 printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4); 370 break; 371 372 case ACK: 373 printf("<block=%d>\n", ntohs(tp->th_block)); 374 break; 375 376 case ERROR: 377 printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg); 378 break; 379 } 380 } 381 382 struct timeval tstart; 383 struct timeval tstop; 384 struct timezone zone; 385 386 startclock() { 387 gettimeofday(&tstart, &zone); 388 } 389 390 stopclock() { 391 gettimeofday(&tstop, &zone); 392 } 393 394 printstats(direction, amount) 395 char *direction; 396 unsigned long amount; 397 { 398 double delta; 399 /* compute delta in 1/10's second units */ 400 delta = ((tstop.tv_sec*10.)+(tstop.tv_usec/100000)) - 401 ((tstart.tv_sec*10.)+(tstart.tv_usec/100000)); 402 delta = delta/10.; /* back to seconds */ 403 printf("%s %d bytes in %.1f seconds", direction, amount, delta); 404 if (verbose) 405 printf(" [%.0f bits/sec]", (amount*8.)/delta); 406 putchar('\n'); 407 } 408 409