Annotation of cci/usr/src/ucb/tftp/tftp.c, revision 1.1

1.1     ! root        1: #ifndef lint
        !             2: static char sccsid[] = "@(#)tftp.c     4.7 (Berkeley) 8/11/83";
        !             3: #endif
        !             4: 
        !             5: /*
        !             6:  * TFTP User Program -- Protocol Machines
        !             7:  */
        !             8: #include <sys/types.h>
        !             9: #include <sys/socket.h>
        !            10: 
        !            11: 
        !            12: #include <netinet/in.h>
        !            13: 
        !            14: #include <arpa/tftp.h>
        !            15: 
        !            16: #include <signal.h>
        !            17: #include <stdio.h>
        !            18: #include <errno.h>
        !            19: #include <setjmp.h>
        !            20: 
        !            21: 
        !            22: /*----- to report system call error -----*/
        !            23: extern int errno;
        !            24: extern struct sockaddr_in sin;
        !            25: extern char mode[];
        !            26: 
        !            27: /*----- various options and their values -----*/
        !            28: extern int     f;
        !            29: extern int     trace;
        !            30: extern int     verbose;
        !            31: extern int     connected;
        !            32: extern int     rexmtval;
        !            33: extern int     maxtimeout;
        !            34: 
        !            35: /*----- control messages -------*/
        !            36: static char    buf[BUFSIZ];
        !            37: 
        !            38: /*----- communication connections ------*/
        !            39: static struct  sockaddr_in to;
        !            40: 
        !            41: /*----- handling asynchronous events ----- */
        !            42: static int     timeout;
        !            43: static jmp_buf timeoutbuf;             /* timer expires */
        !            44: static jmp_buf intrbuf;                /* user abort */
        !            45: 
        !            46: extern char    *inet_ntoa();           /* unix library call */
        !            47: 
        !            48: /*---------------------------------------------------
        !            49:   <<<<<<<<<<<<<<<<<<<<<<<<
        !            50:   <<<<<<< NOTES <<<<<<<<<<  It does not pay to diff this version with
        !            51:   <<<<<<<<<<<<<<<<<<<<<<<<  the original ucb version as this version
        !            52:   <<<<<<<<<<<<<<<<<<<<<<<<  is nearly rewritten.
        !            53: 
        !            54:   Changes:
        !            55: 
        !            56:        .       always report result even though transmitting 0 bytes
        !            57:                in recvfile() and sendfile(). Add local variable haserr
        !            58:                for this purpose.
        !            59: 
        !            60:        .       add global variable "to". 
        !            61:                at start of receiving or sending files, copy daemon address 
        !            62:                "sin" to "to". send request to daemon throught "to". 
        !            63:                when daemon child returns its address, set "to" = address 
        !            64:                of daemon child. from then on, communicate with daemon child 
        !            65:                (through "to").
        !            66:        
        !            67:        .       connect to child daemon for performance and to ensure that
        !            68:                strayed messages are discarded by the system.
        !            69: 
        !            70:        .       close the current file when timed out. 
        !            71:        
        !            72:        .       correct the connect() system call (call syntax was wrong)
        !            73:                in nak().
        !            74: 
        !            75:        .       close the current file and socket when interrupted.
        !            76:  ----------------------------------------------------*/
        !            77: 
        !            78: timer()
        !            79: {
        !            80:        longjmp(timeoutbuf, 1);
        !            81: }
        !            82: 
        !            83: xmitintr()
        !            84: {
        !            85:        alarm(0);               /* turn off alarm */
        !            86:        longjmp(intrbuf, 1);
        !            87: }
        !            88: 
        !            89: /*-----------------------------------------
        !            90:  * Send the requested file.
        !            91:  -----------------------------------------*/
        !            92: sendfile(currentfile, name)
        !            93:        FILE *currentfile;
        !            94:        char *name;
        !            95: {
        !            96:        /*-------- data transfer parameters */
        !            97:        register struct tftphdr *tp = (struct tftphdr *)buf;
        !            98:        register int block = 0; 
        !            99:        int     xamount = 0;            /* # bytes transmitted */
        !           100:        int     xsize; 
        !           101:        int     famount = 0;            /* # bytes read from file */
        !           102:        int     fsize;  
        !           103: 
        !           104:        int     n; 
        !           105:        int     haserr = 0;
        !           106: 
        !           107:        /*-------- connection parameters */
        !           108:        struct sockaddr_in from;
        !           109:        int fromlen;
        !           110: 
        !           111:        /*-------- statistics parameters */
        !           112:        time_t start = time(0)        !           113:        time_t delta;
        !           114: 
        !           115:        /*----- others */
        !           116:        int     (*oldintr)();           /* interrupt handler */
        !           117: 
        !           118:        (void)signal(SIGALRM, timer);
        !           119:        oldintr = signal(SIGINT, xmitintr);
        !           120:        if (setjmp(intrbuf))
        !           121:                goto abort;
        !           122: 
        !           123:        do {
        !           124:                /*----- send request and ack -------*/
        !           125:                timeout = 0;
        !           126:                if (setjmp(timeoutbuf)) {
        !           127:                        timeout += rexmtval;
        !           128:                        if (timeout >= maxtimeout)
        !           129:                                goto expire;
        !           130:                }
        !           131: 
        !           132:                if (trace)
        !           133:                        tpacket("sent", tp, xsize + 4);
        !           134: 
        !           135:                if (block == 0) {
        !           136:                        /* first trip */
        !           137:                        xsize = makerequest(WRQ, name) - 4;
        !           138:                        getsock();
        !           139:                        to = sin;
        !           140:                        n = sendto(f, buf, xsize + 4, 0, (caddr_t)&to, 
        !           141:                                        sizeof (to));
        !           142:                }
        !           143:                else {
        !           144:                        xsize = tftpread(currentfile, tp->th_data, SEGSIZE, 
        !           145:                                        &fsize);
        !           146:                        if (xsize < 0) {
        !           147:                                perror("tftp:sendfile:read fails");
        !           148:                                nak(errno + 100);
        !           149:                                break;
        !           150:                        }
        !           151:                        tp->th_opcode = htons((u_short)DATA);
        !           152:                        tp->th_block = htons((u_short)block);
        !           153:                        n = send(f, buf, xsize+4, 0);
        !           154: #ifdef DEBUG
        !           155:                        fprintf(stderr,"send %d bytes, block %d\n",
        !           156:                                xsize, block);
        !           157: #endif
        !           158:                }
        !           159: 
        !           160:                if (n != xsize + 4) {
        !           161:                        perror("tftp: sendto or send fails");
        !           162:                        haserr++;
        !           163:                        goto abort;
        !           164:                }
        !           165: 
        !           166:                /* get response and data */
        !           167:                do {
        !           168:                        alarm(rexmtval);
        !           169:                        do {
        !           170:                                fromlen = sizeof (from);
        !           171:                                n = recvfrom(f, buf, sizeof (buf), 0,
        !           172:                                    (caddr_t)&from, &fromlen);
        !           173:                        } while (n <= 0);
        !           174:                        alarm(0);
        !           175:                        if (n < 0) {
        !           176:                                perror("tftp: recvfrom fails");
        !           177:                                haserr++;
        !           178:                                goto abort;
        !           179:                        }
        !           180: #ifdef DEBUG
        !           181:                        fprintf(stderr,"sendfile: recv from %s %d\n",
        !           182:                                inet_ntoa(from.sin_addr), from.sin_port);
        !           183: #endif
        !           184:                        if (trace)
        !           185:                                tpacket("received", tp, n, from.sin_port);
        !           186: 
        !           187:                        /* use the address returned by daemon child */
        !           188:                        if (block == 0) {
        !           189:                                /* first trip */
        !           190:                                if (connect(f, (char *)&from, sizeof(from))<0){
        !           191:                                        perror("tftp: connect fails");
        !           192:                                        haserr++;
        !           193:                                        goto abort;
        !           194:                                }
        !           195:                                to.sin_addr = from.sin_addr;
        !           196:                                to.sin_port = from.sin_port;
        !           197:                        }
        !           198: 
        !           199:                        tp->th_opcode = ntohs(tp->th_opcode);
        !           200:                        tp->th_block = ntohs(tp->th_block);
        !           201:                        if (tp->th_opcode == ERROR) {
        !           202:                                printf("Error code %d: %s\n", tp->th_code,
        !           203:                                        tp->th_msg);
        !           204:                                haserr++;
        !           205:                                goto abort;
        !           206:                        }
        !           207: 
        !           208:                } while (tp->th_opcode != ACK || 
        !           209:                         block != tp->th_block);
        !           210: 
        !           211:                if (block > 0) {
        !           212:                        xamount += xsize;
        !           213:                        famount += fsize;
        !           214:                }
        !           215:                block++;
        !           216: 
        !           217:        } while (xsize == SEGSIZE || 
        !           218:                 block == 1);
        !           219: abort:
        !           220: done:
        !           221:        fclose(currentfile);
        !           222:        (void) close(f), f = -1;
        !           223: 
        !           224:        if (haserr == 0 ||
        !           225:            xamount >0) {
        !           226:                delta = time(0) - start;
        !           227:                printf("Read %d bytes and sent %d bytes in %d seconds.\n", 
        !           228:                        famount, xamount, delta);
        !           229:        }
        !           230: 
        !           231:        signal(SIGINT, oldintr); 
        !           232:        oldintr = 0;
        !           233:        return;
        !           234: 
        !           235: expire:
        !           236:        printf("Transfer timed out.\n");
        !           237:        goto abort;
        !           238: }
        !           239: 
        !           240: 
        !           241: /*---------------------------------------------
        !           242:  * Receive a file.
        !           243:  ----------------------------------------*/
        !           244: recvfile(currentfile, name)
        !           245:        FILE *currentfile;
        !           246:        char *name;
        !           247: {
        !           248:        /*----- file transfer bufs -------------*/
        !           249:        register struct tftphdr *tp = (struct tftphdr *)buf;
        !           250:        register int block = 1; 
        !           251:        int     xamount = 0;
        !           252:        int     xsize; 
        !           253:        int     famount = 0;
        !           254:        int     fsize; 
        !           255:        int     firsttrip = 1;
        !           256: 
        !           257:        int     n,m; 
        !           258:        int     haserr = 0;
        !           259:        long    segsize;                        /* for debugging purposes */
        !           260: 
        !           261:        /*----- connection --------*/
        !           262:        struct sockaddr_in from;
        !           263:        int     fromlen; 
        !           264: 
        !           265:        /*----- statistics --------*/
        !           266:        time_t start = time(0)        !           267:        time_t delta;
        !           268: 
        !           269:        /*----- others -------*/
        !           270:        int     (*oldintr)();
        !           271: 
        !           272:        signal(SIGALRM, timer);
        !           273:        oldintr = signal(SIGINT, xmitintr);
        !           274:        if (setjmp(intrbuf))
        !           275:                goto abort;
        !           276: 
        !           277:        /* file transfer */
        !           278:        do {
        !           279: 
        !           280:                /* send request/ acknowledgement */
        !           281:                timeout = 0;
        !           282:                if (setjmp(timeoutbuf)) {
        !           283:                        timeout += rexmtval;
        !           284:                        if (timeout >= maxtimeout)
        !           285:                                goto expire;
        !           286:                }
        !           287:                if (trace)
        !           288:                        tpacket("sent", tp, xsize);
        !           289:                if (firsttrip) {
        !           290:                        xsize = makerequest(RRQ, name);
        !           291:                        getsock();
        !           292:                        to = sin;
        !           293:                        n = sendto(f, buf, xsize, 0, (caddr_t)&to, sizeof(to));
        !           294:                } else {
        !           295:                        tp->th_opcode = htons((u_short)ACK);
        !           296:                        tp->th_block = htons((u_short)(block));
        !           297:                        xsize = 4;
        !           298:                        block++;
        !           299:                        n = send(f, buf, xsize, 0);
        !           300:                }
        !           301:                if (n != xsize) {
        !           302:                        alarm(0);
        !           303:                        perror("tftp: sendto or send fails");
        !           304:                        haserr++;
        !           305:                        goto abort;
        !           306:                }
        !           307: 
        !           308:                /* get response and data */
        !           309:                do {
        !           310:                        alarm(rexmtval);
        !           311:                        do {
        !           312:                                fromlen = sizeof(from);
        !           313:                                n = recvfrom(f, buf, sizeof (buf), 0,
        !           314:                                    (caddr_t)&from, &fromlen);
        !           315:                        } while (n <= 0);
        !           316:                        alarm(0);
        !           317:                        if (n < 0) {
        !           318:                                perror("tftp: recvfrom");
        !           319:                                haserr++;
        !           320:                                goto abort;
        !           321:                        }
        !           322: #ifdef DEBUG
        !           323:                        fprintf(stderr,"recvfile: recv from %s %d, n:%d\n",
        !           324:                                inet_ntoa(from.sin_addr), from.sin_port,n);
        !           325: #endif
        !           326: 
        !           327:                        /* use the address returned by daemon child */
        !           328:                        if (firsttrip) {
        !           329:                                if (connect(f, (char *)&from, sizeof(from))<0){
        !           330:                                        perror("tftp: recvfile: connect fails");
        !           331:                                        haserr++;
        !           332:                                        goto abort;
        !           333:                                }
        !           334:                                to.sin_addr = from.sin_addr;
        !           335:                                to.sin_port = from.sin_port;
        !           336:                                firsttrip = 0;
        !           337:                        }
        !           338: 
        !           339:                        if (trace)
        !           340:                                tpacket("received", tp, n,from.sin_port);
        !           341: 
        !           342:                        tp->th_opcode = ntohs(tp->th_opcode);
        !           343:                        tp->th_block = ntohs(tp->th_block);
        !           344:                        if (tp->th_opcode == ERROR) {
        !           345:                                fprintf(stderr,"Error code %d: %s\n", 
        !           346:                                        tp->th_code, tp->th_msg);
        !           347:                                haserr++;
        !           348:                                goto abort;
        !           349:                        }
        !           350:                } while (tp->th_opcode != DATA || 
        !           351:                         block != tp->th_block);
        !           352: 
        !           353:                /* write to local file */
        !           354:                xsize = n -4;
        !           355:                n = tftpwrite(currentfile, tp->th_data, xsize, &fsize);
        !           356:                if (n < 0) {
        !           357:                        perror("tftp:recvfile():write fails");
        !           358:                        nak(errno + 100);
        !           359:                        break;
        !           360:                }
        !           361:                xamount += xsize;
        !           362:                famount += fsize;
        !           363:        } while (xsize == SEGSIZE);
        !           364: #ifdef DEBUG
        !           365:        fprintf(stderr,"Transfer complete: segsize %d, compare %d\n",
        !           366:                xsize, xsize==SEGSIZE);
        !           367: #endif
        !           368: abort:
        !           369: done:
        !           370:        tp->th_opcode = htons((u_short)ACK);
        !           371:        tp->th_block = htons((u_short)block);
        !           372:        (void) send(f, buf, 4, 0);
        !           373: 
        !           374:        fclose(currentfile);
        !           375:        (void) close(f), f = -1;
        !           376: 
        !           377:        if (haserr == 0||
        !           378:            xamount > 0) {
        !           379:                delta = time(0) - start;
        !           380:                printf("Received %d bytes, wrote %d bytes in %d seconds.\n", 
        !           381:                        xamount, famount, delta);
        !           382:        }
        !           383:        signal(SIGINT, oldintr);
        !           384:        return;
        !           385: 
        !           386: expire:
        !           387:        printf("Transfer timed out\n");
        !           388:        goto abort;
        !           389: }
        !           390: 
        !           391: 
        !           392: /*------------------------------------------------------------
        !           393:   makerequest
        !           394:   ----------------------------------------------------------*/
        !           395: makerequest(request, name)
        !           396:        int request;
        !           397:        char *name;
        !           398: {
        !           399:        register struct tftphdr *tp;
        !           400:        int size;
        !           401:        register char *cp;
        !           402: 
        !           403:        tp = (struct tftphdr *)buf;
        !           404:        tp->th_opcode = htons((u_short)request);
        !           405:        strcpy(tp->th_stuff, name);
        !           406:        size = strlen(name);
        !           407:        cp = tp->th_stuff + strlen(name);
        !           408:        *cp++ = '\0';
        !           409:        strcpy(cp, mode);
        !           410:        cp += sizeof ("netascii") - 1;
        !           411:        *cp++ = '\0';
        !           412:        return (cp - buf);
        !           413: }
        !           414: 
        !           415: struct errmsg {
        !           416:        int     e_code;
        !           417:        char    *e_msg;
        !           418: } errmsgs[] = {
        !           419:        { EUNDEF,       "Undefined error code" },
        !           420:        { ENOTFOUND,    "File not found" },
        !           421:        { EACCESS,      "Access violation" },
        !           422:        { ENOSPACE,     "Disk full or allocation exceeded" },
        !           423:        { EBADOP,       "Illegal TFTP operation" },
        !           424:        { EBADID,       "Unknown transfer ID" },
        !           425:        { EEXISTS,      "File already exists" },
        !           426:        { ENOUSER,      "No such user" },
        !           427:        { -1,           0 }
        !           428: };
        !           429: 
        !           430: /*---------------------------------------------------
        !           431:  * Send a nak packet (error message).
        !           432:  * Error code passed in is one of the
        !           433:  * standard TFTP codes, or a UNIX errno
        !           434:  * offset by 100.
        !           435:  --------------------------------------------------*/
        !           436: nak(error)
        !           437:        int error;
        !           438: {
        !           439:        register struct tftphdr *tp;
        !           440:        int length;
        !           441:        register struct errmsg *pe;
        !           442:        extern char *sys_errlist[];
        !           443: 
        !           444:        tp = (struct tftphdr *)buf;
        !           445:        tp->th_opcode = htons((u_short)ERROR);
        !           446:        tp->th_code = htons((u_short)error);
        !           447:        for (pe = errmsgs; pe->e_code >= 0; pe++)
        !           448:                if (pe->e_code == error)
        !           449:                        break;
        !           450:        if (pe->e_code < 0)
        !           451:                pe->e_msg = sys_errlist[error - 100];
        !           452:        strcpy(tp->th_msg, pe->e_msg);
        !           453:        length = strlen(pe->e_msg) + 4;
        !           454:        if (trace)
        !           455:                tpacket("sent", tp, length);
        !           456:        if (send(f, buf, length, 0) != length) {
        !           457:                perror("tftp:nak: send fails");
        !           458:        }
        !           459: }
        !           460: 
        !           461: /*------------------------------------------------------------
        !           462:   tpackets
        !           463:   ----------------------------------------------------------*/
        !           464: tpacket(s, tp, n, dport)
        !           465:        struct tftphdr *tp;
        !           466:        int n, dport;
        !           467: {
        !           468:        static char *opcodes[] =
        !           469:           { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
        !           470:        register char *cp, *file;
        !           471:        u_short op = ntohs(tp->th_opcode);
        !           472:        char *index();
        !           473: 
        !           474:        if (op < RRQ || op > ERROR)
        !           475:                printf("%s opcode=%x ", s, op);
        !           476:        else
        !           477:                printf("%s %s ", s, opcodes[op]);
        !           478:        switch (op) {
        !           479: 
        !           480:        case RRQ:
        !           481:        case WRQ:
        !           482:                n -= 2;
        !           483:                file = cp = tp->th_stuff;
        !           484:                cp = index(cp, '\0');
        !           485:                printf("<file=%s, mode=%s>\n", file, cp + 1);
        !           486:                break;
        !           487: 
        !           488:        case DATA:
        !           489:                printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
        !           490:                break;
        !           491: 
        !           492:        case ACK:
        !           493:                printf("<block=%d, from port=%d>\n",ntohs(tp->th_block),dport);
        !           494:                break;
        !           495: 
        !           496:        case ERROR:
        !           497:                printf("<code=%d, msglen=%ld, msg=%s>\n", 
        !           498:                        ntohs(tp->th_code),n, tp->th_msg);
        !           499:                break;
        !           500:        }
        !           501: }

unix.superglobalmegacorp.com

This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.