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

Defined functions

makerequest defined in line 275; used 2 times
nak defined in line 314; used 2 times
printstats defined in line 391; used 2 times
recvfile defined in line 172; used 2 times
sendfile defined in line 71; used 2 times
startclock defined in line 383; used 2 times
stopclock defined in line 387; used 2 times
timer defined in line 57; used 2 times
tpacket defined in line 340; used 5 times

Defined variables

ackbuf defined in line 52; used 8 times
errmsgs defined in line 296; used 1 times
sccsid defined in line 21; never used
timeout defined in line 53; used 4 times
timeoutbuf defined in line 55; used 3 times
toplevel defined in line 54; used 1 times
  • in line 63
tstart defined in line 379; used 3 times
tstop defined in line 380; used 3 times
zone defined in line 381; used 2 times

Defined struct's

errmsg defined in line 293; used 2 times
  • in line 317(2)

Defined macros

PKTSIZE defined in line 51; used 2 times
Last modified: 1994-01-11
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 4598
Valid CSS Valid XHTML 1.0 Strict