[BACK]Return to tftp.c CVS log [TXT][DIR] Up to [local] / src / usr.bin / tftp

Annotation of src/usr.bin/tftp/tftp.c, Revision 1.18

1.18    ! mglocker    1: /*     $OpenBSD: tftp.c,v 1.17 2006/07/12 16:58:51 mglocker Exp $      */
1.1       deraadt     2: /*     $NetBSD: tftp.c,v 1.5 1995/04/29 05:55:25 cgd Exp $     */
                      3:
                      4: /*
                      5:  * Copyright (c) 1983, 1993
                      6:  *     The Regents of the University of California.  All rights reserved.
                      7:  *
                      8:  * Redistribution and use in source and binary forms, with or without
                      9:  * modification, are permitted provided that the following conditions
                     10:  * are met:
                     11:  * 1. Redistributions of source code must retain the above copyright
                     12:  *    notice, this list of conditions and the following disclaimer.
                     13:  * 2. Redistributions in binary form must reproduce the above copyright
                     14:  *    notice, this list of conditions and the following disclaimer in the
                     15:  *    documentation and/or other materials provided with the distribution.
1.12      millert    16:  * 3. Neither the name of the University nor the names of its contributors
1.1       deraadt    17:  *    may be used to endorse or promote products derived from this software
                     18:  *    without specific prior written permission.
                     19:  *
                     20:  * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
                     21:  * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
                     22:  * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
                     23:  * ARE DISCLAIMED.  IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
                     24:  * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
                     25:  * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
                     26:  * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
                     27:  * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
                     28:  * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
                     29:  * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
                     30:  * SUCH DAMAGE.
                     31:  */
                     32:
                     33: #ifndef lint
                     34: #if 0
                     35: static char sccsid[] = "@(#)tftp.c     8.1 (Berkeley) 6/6/93";
                     36: #endif
1.17      mglocker   37: static const char rcsid[] =
1.18    ! mglocker   38:     "$OpenBSD: tftp.c,v 1.17 2006/07/12 16:58:51 mglocker Exp $";
1.1       deraadt    39: #endif /* not lint */
                     40:
                     41: /*
                     42:  * TFTP User Program -- Protocol Machines
1.17      mglocker   43:  *
                     44:  * This version includes many modifications by Jim Guyton <guyton@rand-unix>
1.1       deraadt    45:  */
1.16      claudio    46:
1.1       deraadt    47: #include <sys/types.h>
                     48: #include <sys/socket.h>
                     49: #include <sys/time.h>
                     50:
                     51: #include <netinet/in.h>
                     52: #include <arpa/tftp.h>
                     53:
1.17      mglocker   54: #include <err.h>
1.1       deraadt    55: #include <errno.h>
1.16      claudio    56: #include <poll.h>
1.1       deraadt    57: #include <signal.h>
                     58: #include <stdio.h>
1.11      henning    59: #include <stddef.h>
1.1       deraadt    60: #include <string.h>
                     61: #include <unistd.h>
                     62:
                     63: #include "extern.h"
                     64: #include "tftpsubs.h"
                     65:
1.16      claudio    66: #define        PKTSIZE SEGSIZE + 4
                     67:
1.17      mglocker   68: static int     makerequest(int, const char *, struct tftphdr *, const char *);
                     69: static void    nak(int);
                     70: static void    tpacket(const char *, struct tftphdr *, int);
                     71: static void    startclock(void);
                     72: static void    stopclock(void);
                     73: static void    printstats(const char *, unsigned long);
                     74: static void    printtimeout(void);
                     75:
                     76: extern struct sockaddr_in       peeraddr;      /* filled in by main */
                     77: extern int                      f;             /* the opened socket */
                     78: extern int                      trace;
                     79: extern int                      verbose;
                     80: extern int                      rexmtval;
                     81: extern int                      maxtimeout;
1.16      claudio    82: extern FILE                    *file;
1.17      mglocker   83: extern volatile sig_atomic_t    intrflag;
1.16      claudio    84:
1.17      mglocker   85: char           ackbuf[PKTSIZE];
1.16      claudio    86: struct timeval tstart;
                     87: struct timeval tstop;
                     88:
                     89: struct errmsg {
1.17      mglocker   90:        int      e_code;
1.16      claudio    91:        char    *e_msg;
                     92: } errmsgs[] = {
                     93:        { EUNDEF,       "Undefined error code" },
                     94:        { ENOTFOUND,    "File not found" },
                     95:        { EACCESS,      "Access violation" },
                     96:        { ENOSPACE,     "Disk full or allocation exceeded" },
                     97:        { EBADOP,       "Illegal TFTP operation" },
                     98:        { EBADID,       "Unknown transfer ID" },
                     99:        { EEXISTS,      "File already exists" },
                    100:        { ENOUSER,      "No such user" },
                    101:        { -1,           NULL }
                    102: };
                    103:
1.1       deraadt   104: /*
                    105:  * Send the requested file.
                    106:  */
                    107: void
1.14      deraadt   108: sendfile(int fd, char *name, char *mode)
1.1       deraadt   109: {
1.17      mglocker  110:        struct tftphdr          *dp, *ap; /* data and ack packets */
                    111:        struct sockaddr_in       from;
                    112:        struct pollfd            pfd[1];
                    113:        unsigned long            amount;
                    114:        int                      convert; /* true if converting crlf -> lf */
                    115:        int                      n, nfds, error, fromlen, timeouts, block, size;
1.1       deraadt   116:
                    117:        startclock();           /* start stat's clock */
                    118:        dp = r_init();          /* reset fillbuf/read-ahead code */
                    119:        ap = (struct tftphdr *)ackbuf;
                    120:        file = fdopen(fd, "r");
                    121:        convert = !strcmp(mode, "netascii");
                    122:        block = 0;
                    123:        amount = 0;
                    124:
                    125:        do {
1.16      claudio   126:                /* read data from file */
                    127:                if (!block)
1.1       deraadt   128:                        size = makerequest(WRQ, name, dp, mode) - 4;
                    129:                else {
1.18    ! mglocker  130:                        size = readit(file, &dp, convert, SEGSIZE);
1.1       deraadt   131:                        if (size < 0) {
                    132:                                nak(errno + 100);
                    133:                                break;
                    134:                        }
                    135:                        dp->th_opcode = htons((u_short)DATA);
                    136:                        dp->th_block = htons((u_short)block);
                    137:                }
1.16      claudio   138:
                    139:                /* send data to server and wait for server ACK */
                    140:                for (timeouts = 0, error = 0; !intrflag;) {
                    141:                        if (timeouts == maxtimeout) {
                    142:                                printtimeout();
                    143:                                goto abort;
                    144:                        }
                    145:
                    146:                        if (!error) {
                    147:                                if (trace)
                    148:                                        tpacket("sent", dp, size + 4);
                    149:                                if (sendto(f, dp, size + 4, 0,
                    150:                                    (struct sockaddr *)&peeraddr,
                    151:                                    sizeof(peeraddr)) != size + 4) {
                    152:                                        warn("sendto");
                    153:                                        goto abort;
                    154:                                }
1.18    ! mglocker  155:                                read_ahead(file, convert, SEGSIZE);
1.16      claudio   156:                        }
                    157:                        error = 0;
                    158:
                    159:                        pfd[0].fd = f;
                    160:                        pfd[0].events = POLLIN;
                    161:                        nfds = poll(pfd, 1, rexmtval * 1000);
                    162:                        if (nfds == 0) {
                    163:                                timeouts++;
                    164:                                continue;
                    165:                        }
                    166:                        if (nfds == -1) {
                    167:                                error = 1;
                    168:                                if (errno == EINTR)
                    169:                                        continue;
                    170:                                warn("poll");
                    171:                                goto abort;
                    172:                        }
                    173:                        fromlen = sizeof(from);
                    174:                        n = recvfrom(f, ackbuf, sizeof(ackbuf), 0,
                    175:                            (struct sockaddr *)&from, &fromlen);
                    176:                        if (n == 0) {
                    177:                                warn("recvfrom");
                    178:                                goto abort;
                    179:                        }
                    180:                        if (n == -1) {
                    181:                                error = 1;
                    182:                                if (errno == EINTR)
                    183:                                        continue;
1.7       mickey    184:                                warn("recvfrom");
1.1       deraadt   185:                                goto abort;
                    186:                        }
                    187:                        peeraddr.sin_port = from.sin_port;      /* added */
                    188:                        if (trace)
                    189:                                tpacket("received", ap, n);
                    190:                        ap->th_opcode = ntohs(ap->th_opcode);
                    191:                        ap->th_block = ntohs(ap->th_block);
1.16      claudio   192:
1.1       deraadt   193:                        if (ap->th_opcode == ERROR) {
1.16      claudio   194:                                printf("Error code %d: %s\n",
                    195:                                    ap->th_code, ap->th_msg);
1.1       deraadt   196:                                goto abort;
                    197:                        }
                    198:                        if (ap->th_opcode == ACK) {
                    199:                                int j;
1.16      claudio   200:                                if (ap->th_block == block)
1.1       deraadt   201:                                        break;
1.16      claudio   202:                                /* re-synchronize with other side */
1.1       deraadt   203:                                j = synchnet(f);
1.15      deraadt   204:                                if (j && trace)
                    205:                                        printf("discarded %d packets\n", j);
1.16      claudio   206:                                if (ap->th_block == (block - 1))
                    207:                                        continue;
1.1       deraadt   208:                        }
1.16      claudio   209:                        error = 1;      /* received packet does not match */
1.1       deraadt   210:                }
1.16      claudio   211:
1.1       deraadt   212:                if (block > 0)
                    213:                        amount += size;
                    214:                block++;
1.16      claudio   215:        } while ((size == SEGSIZE || block == 1) && !intrflag);
                    216:
1.1       deraadt   217: abort:
                    218:        fclose(file);
                    219:        stopclock();
1.16      claudio   220:        if (amount > 0) {
                    221:                if (intrflag)
                    222:                        putchar('\n');
1.1       deraadt   223:                printstats("Sent", amount);
1.16      claudio   224:        }
1.1       deraadt   225: }
                    226:
                    227: /*
                    228:  * Receive a file.
                    229:  */
                    230: void
1.14      deraadt   231: recvfile(int fd, char *name, char *mode)
1.1       deraadt   232: {
1.17      mglocker  233:        struct tftphdr          *dp, *ap; /* data and ack packets */
                    234:        struct sockaddr_in       from;
                    235:        struct pollfd            pfd[1];
                    236:        unsigned long            amount;
                    237:        int                      convert; /* true if converting crlf -> lf */
                    238:        int                      n, nfds, error, fromlen, timeouts, block, size;
                    239:        int                      firsttrip;
1.1       deraadt   240:
1.16      claudio   241:        startclock();           /* start stat's clock */
                    242:        dp = w_init();          /* reset fillbuf/read-ahead code */
1.1       deraadt   243:        ap = (struct tftphdr *)ackbuf;
                    244:        file = fdopen(fd, "w");
                    245:        convert = !strcmp(mode, "netascii");
1.16      claudio   246:        n = 0;
1.1       deraadt   247:        block = 1;
1.16      claudio   248:        amount = 0;
1.1       deraadt   249:        firsttrip = 1;
                    250:
                    251:        do {
1.16      claudio   252:                /* create new ACK packet */
1.1       deraadt   253:                if (firsttrip) {
                    254:                        size = makerequest(RRQ, name, ap, mode);
                    255:                        firsttrip = 0;
                    256:                } else {
                    257:                        ap->th_opcode = htons((u_short)ACK);
                    258:                        ap->th_block = htons((u_short)(block));
                    259:                        size = 4;
                    260:                        block++;
                    261:                }
1.16      claudio   262:
                    263:                /* send ACK to server and wait for server data */
                    264:                for (timeouts = 0, error = 0; !intrflag;) {
                    265:                        if (timeouts == maxtimeout) {
                    266:                                printtimeout();
                    267:                                goto abort;
                    268:                        }
                    269:
                    270:                        if (!error) {
                    271:                                if (trace)
                    272:                                        tpacket("sent", ap, size);
                    273:                                if (sendto(f, ackbuf, size, 0,
                    274:                                    (struct sockaddr *)&peeraddr,
                    275:                                    sizeof(peeraddr)) != size) {
                    276:                                        warn("sendto");
                    277:                                        goto abort;
                    278:                                }
                    279:                                write_behind(file, convert);
                    280:                        }
                    281:                        error = 0;
                    282:
                    283:                        pfd[0].fd = f;
                    284:                        pfd[0].events = POLLIN;
                    285:                        nfds = poll(pfd, 1, rexmtval * 1000);
                    286:                        if (nfds == 0) {
                    287:                                timeouts++;
                    288:                                continue;
                    289:                        }
                    290:                        if (nfds == -1) {
                    291:                                error = 1;
                    292:                                if (errno == EINTR)
                    293:                                        continue;
                    294:                                warn("poll");
                    295:                                goto abort;
                    296:                        }
                    297:                        fromlen = sizeof(from);
                    298:                        n = recvfrom(f, dp, PKTSIZE, 0,
                    299:                            (struct sockaddr *)&from, &fromlen);
                    300:                        if (n == 0) {
                    301:                                warn("recvfrom");
                    302:                                goto abort;
                    303:                        }
                    304:                        if (n == -1) {
                    305:                                error = 1;
                    306:                                if (errno == EINTR)
                    307:                                        continue;
1.7       mickey    308:                                warn("recvfrom");
1.1       deraadt   309:                                goto abort;
                    310:                        }
                    311:                        peeraddr.sin_port = from.sin_port;      /* added */
                    312:                        if (trace)
                    313:                                tpacket("received", dp, n);
                    314:                        dp->th_opcode = ntohs(dp->th_opcode);
                    315:                        dp->th_block = ntohs(dp->th_block);
1.16      claudio   316:
1.1       deraadt   317:                        if (dp->th_opcode == ERROR) {
1.16      claudio   318:                                printf("Error code %d: %s\n",
                    319:                                    dp->th_code, dp->th_msg);
1.1       deraadt   320:                                goto abort;
                    321:                        }
                    322:                        if (dp->th_opcode == DATA) {
                    323:                                int j;
1.16      claudio   324:                                if (dp->th_block == block)
                    325:                                        break;
                    326:                                /* re-synchronize with other side */
1.1       deraadt   327:                                j = synchnet(f);
1.15      deraadt   328:                                if (j && trace)
1.1       deraadt   329:                                        printf("discarded %d packets\n", j);
1.16      claudio   330:                                if (dp->th_block == (block - 1))
                    331:                                        continue;
1.1       deraadt   332:                        }
1.16      claudio   333:                        error = 1;      /* received packet does not match */
1.1       deraadt   334:                }
1.16      claudio   335:
                    336:                /* write data to file */
1.1       deraadt   337:                size = writeit(file, &dp, n - 4, convert);
                    338:                if (size < 0) {
                    339:                        nak(errno + 100);
                    340:                        break;
                    341:                }
                    342:                amount += size;
1.16      claudio   343:        } while (size == SEGSIZE && !intrflag);
                    344:
                    345: abort:
                    346:        /* ok to ack, since user has seen err msg */
                    347:        ap->th_opcode = htons((u_short)ACK);
1.1       deraadt   348:        ap->th_block = htons((u_short)block);
1.17      mglocker  349:        (void)sendto(f, ackbuf, 4, 0, (struct sockaddr *)&peeraddr,
1.1       deraadt   350:            sizeof(peeraddr));
1.16      claudio   351:        write_behind(file, convert);    /* flush last buffer */
                    352:
1.1       deraadt   353:        fclose(file);
                    354:        stopclock();
1.16      claudio   355:        if (amount > 0) {
                    356:                if (intrflag)
                    357:                        putchar('\n');
1.1       deraadt   358:                printstats("Received", amount);
1.16      claudio   359:        }
1.1       deraadt   360: }
                    361:
                    362: static int
1.14      deraadt   363: makerequest(int request, const char *name, struct tftphdr *tp,
                    364:     const char *mode)
1.1       deraadt   365: {
1.17      mglocker  366:        char    *cp;
                    367:        int      len, pktlen;
1.1       deraadt   368:
                    369:        tp->th_opcode = htons((u_short)request);
                    370:        cp = tp->th_stuff;
1.11      henning   371:        pktlen = PKTSIZE - offsetof(struct tftphdr, th_stuff);
                    372:        len = strlen(name) + 1;
                    373:        strlcpy(cp, name, pktlen);
                    374:        strlcpy(cp + len, mode, pktlen - len);
                    375:        len += strlen(mode) + 1;
1.17      mglocker  376:
1.11      henning   377:        return (cp + len - (char *)tp);
1.1       deraadt   378: }
                    379:
                    380: /*
                    381:  * Send a nak packet (error message).
                    382:  * Error code passed in is one of the
                    383:  * standard TFTP codes, or a UNIX errno
                    384:  * offset by 100.
                    385:  */
                    386: static void
1.14      deraadt   387: nak(int error)
1.1       deraadt   388: {
1.17      mglocker  389:        struct errmsg   *pe;
                    390:        struct tftphdr  *tp;
                    391:        int              length;
1.1       deraadt   392:
                    393:        tp = (struct tftphdr *)ackbuf;
                    394:        tp->th_opcode = htons((u_short)ERROR);
                    395:        tp->th_code = htons((u_short)error);
                    396:        for (pe = errmsgs; pe->e_code >= 0; pe++)
                    397:                if (pe->e_code == error)
                    398:                        break;
                    399:        if (pe->e_code < 0) {
                    400:                pe->e_msg = strerror(error - 100);
                    401:                tp->th_code = EUNDEF;
                    402:        }
1.8       mpech     403:        length = strlcpy(tp->th_msg, pe->e_msg, sizeof(ackbuf)) + 5;
                    404:        if (length > sizeof(ackbuf))
                    405:                length = sizeof(ackbuf);
1.1       deraadt   406:        if (trace)
                    407:                tpacket("sent", tp, length);
                    408:        if (sendto(f, ackbuf, length, 0, (struct sockaddr *)&peeraddr,
                    409:            sizeof(peeraddr)) != length)
1.7       mickey    410:                warn("nak");
1.1       deraadt   411: }
                    412:
                    413: static void
1.14      deraadt   414: tpacket(const char *s, struct tftphdr *tp, int n)
1.1       deraadt   415: {
1.17      mglocker  416:        char            *cp, *file;
                    417:        static char     *opcodes[] =
1.16      claudio   418:            { "#0", "RRQ", "WRQ", "DATA", "ACK", "ERROR" };
1.17      mglocker  419:
1.1       deraadt   420:        u_short op = ntohs(tp->th_opcode);
                    421:
                    422:        if (op < RRQ || op > ERROR)
                    423:                printf("%s opcode=%x ", s, op);
                    424:        else
                    425:                printf("%s %s ", s, opcodes[op]);
1.16      claudio   426:
1.1       deraadt   427:        switch (op) {
                    428:        case RRQ:
                    429:        case WRQ:
                    430:                n -= 2;
                    431:                file = cp = tp->th_stuff;
1.3       millert   432:                cp = strchr(cp, '\0');
1.1       deraadt   433:                printf("<file=%s, mode=%s>\n", file, cp + 1);
                    434:                break;
                    435:        case DATA:
                    436:                printf("<block=%d, %d bytes>\n", ntohs(tp->th_block), n - 4);
                    437:                break;
                    438:        case ACK:
                    439:                printf("<block=%d>\n", ntohs(tp->th_block));
                    440:                break;
                    441:        case ERROR:
                    442:                printf("<code=%d, msg=%s>\n", ntohs(tp->th_code), tp->th_msg);
                    443:                break;
                    444:        }
                    445: }
                    446:
                    447: static void
1.13      deraadt   448: startclock(void)
1.1       deraadt   449: {
1.17      mglocker  450:        (void)gettimeofday(&tstart, NULL);
1.1       deraadt   451: }
                    452:
                    453: static void
1.13      deraadt   454: stopclock(void)
1.1       deraadt   455: {
1.17      mglocker  456:        (void)gettimeofday(&tstop, NULL);
1.1       deraadt   457: }
                    458:
                    459: static void
1.14      deraadt   460: printstats(const char *direction, unsigned long amount)
1.1       deraadt   461: {
1.17      mglocker  462:        double  delta;
1.15      deraadt   463:
                    464:        /* compute delta in 1/10's second units */
1.16      claudio   465:        delta = ((tstop.tv_sec * 10.) + (tstop.tv_usec / 100000)) -
                    466:            ((tstart.tv_sec * 10.) + (tstart.tv_usec / 100000));
                    467:        delta = delta / 10.;    /* back to seconds */
1.6       deraadt   468:        printf("%s %lu bytes in %.1f seconds", direction, amount, delta);
1.1       deraadt   469:        if (verbose)
1.16      claudio   470:                printf(" [%.0f bits/sec]", (amount * 8.) / delta);
1.1       deraadt   471:        putchar('\n');
                    472: }
                    473:
                    474: static void
1.16      claudio   475: printtimeout(void)
1.1       deraadt   476: {
1.16      claudio   477:        printf("Transfer timed out.\n");
1.1       deraadt   478: }