Annotation of cci/usr/src/ucb/tftp/tftp.c, revision 1.1.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.