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