# 2.11BSD#431 - /usr/src/ucb/tftp/tftp.c

##### Functions

    makerequest       X
    nak               X
    printstats        X
    recvfile          X
    sendfile          X
    startclock        X
    stopclock         X
    timer             X
    tpacket           X

##### Variables

    ackbuf            X
    errmsgs           X
    timeout           X
    timeoutbuf        X
    toplevel          X
    tstart            X
    tstop             X
    zone              X

##### Macros

    PKTSIZE           X

##### struct's

    errmsg            X

       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

- in line 94, 195

nak defined in line 314; used 2 times

- in line 99, 259

printstats defined in line 391; used 2 times

- in line 166, 272

recvfile defined in line 172; used 2 times

- in /usr/src/ucb/tftp/main.c line 413, 426

sendfile defined in line 71; used 2 times

- in /usr/src/ucb/tftp/main.c line 324, 342

startclock defined in line 383; used 2 times

- in line 85, 186

stopclock defined in line 387; used 2 times

- in line 164, 270

timer defined in line 57; used 2 times

- in line 91, 192

tpacket defined in line 340; used 5 times

- in line 109, 130, 207, 229, 335

#### Defined variables

ackbuf defined in line 52; used 8 times

- in line 87, 120(2), 188, 208, 267, 322, 336

errmsgs defined in line 296; used 1 times

- in line 325

sccsid defined in line 21; never used
timeout defined in line 53; used 4 times

- in line 60-61(2), 105, 203

timeoutbuf defined in line 55; used 3 times

- in line 65, 106, 204

toplevel defined in line 54; used 1 times

- in line 63

tstart defined in line 379; used 3 times

- in line 384, 398(2)

tstop defined in line 380; used 3 times

- in line 388, 397(2)

zone defined in line 381; used 2 times

- in line 384-388(2)

#### 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

- in line 52, 219

Last modified: 1994-01-11 Generated: 2016-12-26 | Generated by src2html V0.67 page hit count: 1993 |