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

Annotation of src/usr.bin/tftp/tftpsubs.c, Revision 1.12

1.12    ! mglocker    1: /*     $OpenBSD: tftpsubs.c,v 1.11 2006/07/20 09:42:44 mglocker Exp $  */
1.1       deraadt     2: /*     $NetBSD: tftpsubs.c,v 1.3 1994/12/08 09:51:31 jtc 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.6       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[] = "@(#)tftpsubs.c 8.1 (Berkeley) 6/6/93";
                     36: #endif
1.10      mglocker   37: static const char rcsid[] =
1.12    ! mglocker   38:     "$OpenBSD: tftpsubs.c,v 1.11 2006/07/20 09:42:44 mglocker Exp $";
1.1       deraadt    39: #endif /* not lint */
                     40:
1.10      mglocker   41: /*
                     42:  * Simple minded read-ahead/write-behind subroutines for tftp user and
                     43:  * server.  Written originally with multiple buffers in mind, but current
                     44:  * implementation has two buffer logic wired in.
                     45:  *
                     46:  * Todo:  add some sort of final error check so when the write-buffer
                     47:  * is finally flushed, the caller can detect if the disk filled up
                     48:  * (or had an i/o error) and return a nak to the other side.
                     49:  *
                     50:  *                     Jim Guyton 10/85
1.1       deraadt    51:  */
                     52:
                     53: #include <sys/types.h>
                     54: #include <sys/socket.h>
                     55: #include <sys/ioctl.h>
1.10      mglocker   56:
1.1       deraadt    57: #include <netinet/in.h>
                     58: #include <arpa/tftp.h>
                     59:
                     60: #include <stdio.h>
                     61: #include <unistd.h>
                     62:
                     63: #include "tftpsubs.h"
                     64:
1.10      mglocker   65:                                        /* values for bf.counter */
                     66: #define BF_ALLOC       -3              /* alloc'd but not yet filled */
                     67: #define BF_FREE                -2              /* free */
                     68: /* [-1 .. SEGSIZE] = size of data in the data buffer */
                     69:
                     70: static struct tftphdr  *rw_init(int);
1.1       deraadt    71:
                     72: struct bf {
1.11      mglocker   73:        int     counter;                /* size of data in buffer, or flag */
                     74:        char    buf[SEGSIZE_MAX + 4];   /* room for data packet */
1.1       deraadt    75: } bfs[2];
                     76:
1.10      mglocker   77: static int     nextone;        /* index of next buffer to use */
                     78: static int     current;        /* index of buffer in use */
1.1       deraadt    79:                                /* control flags for crlf conversions */
1.10      mglocker   80: int            newline = 0;    /* fillbuf: in middle of newline expansion */
                     81: int            prevchar = -1;  /* putbuf: previous char (cr check) */
1.1       deraadt    82:
1.7       deraadt    83: struct tftphdr *
                     84: w_init(void)
                     85: {
1.10      mglocker   86:        return (rw_init(0));    /* write-behind */
1.7       deraadt    87: }
                     88:
                     89: struct tftphdr *
                     90: r_init(void)
                     91: {
1.10      mglocker   92:        return (rw_init(1));    /* read-ahead */
1.7       deraadt    93: }
1.1       deraadt    94:
1.10      mglocker   95: /*
                     96:  * Init for either read-ahead or write-behind.
                     97:  * Zero for write-behind, one for read-head.
                     98:  */
1.1       deraadt    99: static struct tftphdr *
1.7       deraadt   100: rw_init(int x)
1.1       deraadt   101: {
1.10      mglocker  102:        newline = 0;                    /* init crlf flag */
1.1       deraadt   103:        prevchar = -1;
1.12    ! mglocker  104:        bfs[0].counter = BF_ALLOC;      /* pass out the first buffer */
1.1       deraadt   105:        current = 0;
                    106:        bfs[1].counter = BF_FREE;
1.10      mglocker  107:        nextone = x;                    /* ahead or behind? */
                    108:
                    109:        return ((struct tftphdr *)bfs[0].buf);
1.1       deraadt   110: }
                    111:
1.10      mglocker  112: /*
                    113:  * Have emptied current buffer by sending to net and getting ack.
                    114:  * Free it and return next buffer filled with data.
1.1       deraadt   115:  */
                    116: int
1.11      mglocker  117: readit(FILE *file, struct tftphdr **dpp, int convert, int segment_size)
1.1       deraadt   118: {
1.10      mglocker  119:        struct bf       *b;
                    120:
                    121:        bfs[current].counter = BF_FREE;         /* free old one */
                    122:        current = !current;                     /* "incr" current */
1.1       deraadt   123:
1.10      mglocker  124:        b = &bfs[current];                      /* look at new buffer */
                    125:        if (b->counter == BF_FREE)              /* if it's empty */
1.11      mglocker  126:                read_ahead(file, convert, segment_size);        /* fill it */
1.10      mglocker  127:        /* assert(b->counter != BF_FREE); */    /* check */
                    128:        *dpp = (struct tftphdr *)b->buf;        /* set caller's ptr */
1.1       deraadt   129:
1.10      mglocker  130:        return (b->counter);
1.1       deraadt   131: }
                    132:
                    133: /*
1.10      mglocker  134:  * Fill the input buffer, doing ascii conversions if requested.
                    135:  * Conversions are lf -> cr, lf and cr -> cr, nul.
1.1       deraadt   136:  */
                    137: void
1.11      mglocker  138: read_ahead(FILE *file, int convert, int segment_size)
1.1       deraadt   139: {
1.10      mglocker  140:        int              i;
                    141:        char            *p;
                    142:        int              c;
                    143:        struct bf       *b;
                    144:        struct tftphdr  *dp;
1.1       deraadt   145:
1.10      mglocker  146:        b = &bfs[nextone];                      /* look at "next" buffer */
                    147:        if (b->counter != BF_FREE)              /* nop if not free */
1.1       deraadt   148:                return;
1.10      mglocker  149:        nextone = !nextone;                     /* "incr" next buffer ptr */
1.1       deraadt   150:
                    151:        dp = (struct tftphdr *)b->buf;
                    152:
                    153:        if (convert == 0) {
1.11      mglocker  154:                b->counter = read(fileno(file), dp->th_data, segment_size);
1.1       deraadt   155:                return;
                    156:        }
                    157:
                    158:        p = dp->th_data;
1.11      mglocker  159:        for (i = 0; i < segment_size; i++) {
1.1       deraadt   160:                if (newline) {
                    161:                        if (prevchar == '\n')
1.10      mglocker  162:                                c = '\n';       /* lf to cr, lf */
1.9       deraadt   163:                        else
1.10      mglocker  164:                                c = '\0';       /* cr to cr, nul */
1.1       deraadt   165:                        newline = 0;
1.9       deraadt   166:                } else {
1.1       deraadt   167:                        c = getc(file);
1.10      mglocker  168:                        if (c == EOF)
                    169:                                break;
1.1       deraadt   170:                        if (c == '\n' || c == '\r') {
                    171:                                prevchar = c;
                    172:                                c = '\r';
                    173:                                newline = 1;
                    174:                        }
                    175:                }
                    176:               *p++ = c;
                    177:        }
                    178:        b->counter = (int)(p - dp->th_data);
                    179: }
                    180:
1.10      mglocker  181: /*
                    182:  * Update count associated with the buffer, get new buffer
                    183:  * from the queue.  Calls write_behind only if next buffer not
                    184:  * available.
1.1       deraadt   185:  */
                    186: int
1.7       deraadt   187: writeit(FILE *file, struct tftphdr **dpp, int ct, int convert)
1.1       deraadt   188: {
1.10      mglocker  189:        bfs[current].counter = ct;              /* set size of data to write */
                    190:        current = !current;                     /* switch to other buffer */
                    191:        if (bfs[current].counter != BF_FREE)    /* if not free */
                    192:                /* flush it */
                    193:                (void)write_behind(file, convert);
                    194:        bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */
1.1       deraadt   195:        *dpp =  (struct tftphdr *)bfs[current].buf;
1.10      mglocker  196:
                    197:        return (ct);                            /* this is a lie of course */
1.1       deraadt   198: }
                    199:
                    200: /*
                    201:  * Output a buffer to a file, converting from netascii if requested.
1.10      mglocker  202:  * CR, NUL -> CR and CR, LF -> LF.
1.1       deraadt   203:  * Note spec is undefined if we get CR as last byte of file or a
                    204:  * CR followed by anything else.  In this case we leave it alone.
1.10      mglocker  205:  */
1.1       deraadt   206: int
1.7       deraadt   207: write_behind(FILE *file, int convert)
1.1       deraadt   208: {
1.10      mglocker  209:        char            *buf;
                    210:        int              count;
                    211:        int              ct;
                    212:        char            *p;
                    213:        int              c; /* current character */
                    214:        struct bf       *b;
                    215:        struct tftphdr  *dp;
1.1       deraadt   216:
                    217:        b = &bfs[nextone];
1.10      mglocker  218:        if (b->counter < -1)            /* anything to flush? */
                    219:                return (0);             /* just nop if nothing to do */
1.1       deraadt   220:
1.10      mglocker  221:        count = b->counter;             /* remember byte count */
                    222:        b->counter = BF_FREE;           /* reset flag */
1.1       deraadt   223:        dp = (struct tftphdr *)b->buf;
1.10      mglocker  224:        nextone = !nextone;             /* incr for next time */
1.1       deraadt   225:        buf = dp->th_data;
                    226:
1.10      mglocker  227:        if (count <= 0)                 /* nak logic? */
                    228:                return (-1);
1.1       deraadt   229:
                    230:        if (convert == 0)
1.10      mglocker  231:                return (write(fileno(file), buf, count));
1.1       deraadt   232:
                    233:        p = buf;
                    234:        ct = count;
1.10      mglocker  235:        while (ct--) {                          /* loop over the buffer */
                    236:                c = *p++;                       /* pick up a character */
                    237:                if (prevchar == '\r') {         /* if prev char was cr */
                    238:                        if (c == '\n')          /* if have cr,lf then just */
                    239:                                /* smash lf on top of the cr */
                    240:                                fseek(file, -1, 1);
                    241:                        else if (c == '\0')     /* if have cr,nul then */
                    242:                                goto skipit;    /* just skip over the putc */
                    243:                        /* FALLTHROUGH */
1.9       deraadt   244:                }
                    245:                putc(c, file);
1.1       deraadt   246: skipit:
1.9       deraadt   247:                prevchar = c;
1.1       deraadt   248:        }
1.10      mglocker  249:
                    250:        return (count);
1.1       deraadt   251: }
                    252:
1.10      mglocker  253: /*
                    254:  * When an error has occurred, it is possible that the two sides
1.1       deraadt   255:  * are out of synch.  Ie: that what I think is the other side's
                    256:  * response to packet N is really their response to packet N-1.
                    257:  *
                    258:  * So, to try to prevent that, we flush all the input queued up
                    259:  * for us on the network connection on our host.
                    260:  *
                    261:  * We return the number of packets we flushed (mostly for reporting
                    262:  * when trace is active).
                    263:  */
                    264: int
1.7       deraadt   265: synchnet(int f)
1.1       deraadt   266: {
1.10      mglocker  267:        int                     i, j = 0;
1.11      mglocker  268:        char                    rbuf[SEGSIZE_MIN];
1.10      mglocker  269:        struct sockaddr_in      from;
                    270:        socklen_t               fromlen;
1.1       deraadt   271:
1.10      mglocker  272:        for (;;) {
                    273:                (void)ioctl(f, FIONREAD, &i);
1.1       deraadt   274:                if (i) {
                    275:                        j++;
1.10      mglocker  276:                        fromlen = sizeof(from);
                    277:                        (void)recvfrom(f, rbuf, sizeof(rbuf), 0,
1.9       deraadt   278:                            (struct sockaddr *)&from, &fromlen);
1.10      mglocker  279:                } else
                    280:                        return (j);
1.1       deraadt   281:        }
                    282: }