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

Defined functions

makerequest defined in line 262; used 2 times
nak defined in line 301; used 2 times
printstats defined in line 378; used 2 times
recvfile defined in line 159; used 2 times
sendfile defined in line 58; used 2 times
startclock defined in line 370; used 2 times
stopclock defined in line 374; used 2 times
timer defined in line 44; used 2 times
tpacket defined in line 327; used 5 times

Defined variables

ackbuf defined in line 39; used 8 times
errmsgs defined in line 283; used 1 times
sccsid defined in line 8; never used
timeout defined in line 40; used 4 times
timeoutbuf defined in line 42; used 3 times
toplevel defined in line 41; used 1 times
  • in line 50
tstart defined in line 366; used 3 times
tstop defined in line 367; used 3 times
zone defined in line 368; used 2 times

Defined struct's

errmsg defined in line 280; used 2 times
  • in line 306(2)

Defined macros

PKTSIZE defined in line 38; used 2 times
Last modified: 1986-02-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1753
Valid CSS Valid XHTML 1.0 Strict