1: /*
   2:  * Copyright (c) 1985 Regents of the University of California.
   3:  * All rights reserved.  The Berkeley software License Agreement
   4:  * specifies the terms and conditions for redistribution.
   5:  */
   6: 
   7: #ifndef lint
   8: static char sccsid[] = "@(#)tftpsubs.c	1.2 (Berkeley) 2/7/86";
   9: #endif not lint
  10: 
  11: /* Simple minded read-ahead/write-behind subroutines for tftp user and
  12:    server.  Written originally with multiple buffers in mind, but current
  13:    implementation has two buffer logic wired in.
  14: 
  15:    Todo:  add some sort of final error check so when the write-buffer
  16:    is finally flushed, the caller can detect if the disk filled up
  17:    (or had an i/o error) and return a nak to the other side.
  18: 
  19: 			Jim Guyton 10/85
  20:  */
  21: 
  22: #include <sys/types.h>
  23: #include <sys/socket.h>
  24: #include <sys/ioctl.h>
  25: #include <netinet/in.h>
  26: #include <arpa/tftp.h>
  27: #include <stdio.h>
  28: 
  29: #define PKTSIZE SEGSIZE+4       /* should be moved to tftp.h */
  30: 
  31: struct bf {
  32:     int counter;            /* size of data in buffer, or flag */
  33:     char buf[PKTSIZE];      /* room for data packet */
  34: } bfs[2];
  35: 
  36:                 /* Values for bf.counter  */
  37: #define BF_ALLOC -3             /* alloc'd but not yet filled */
  38: #define BF_FREE  -2             /* free */
  39: /* [-1 .. SEGSIZE] = size of data in the data buffer */
  40: 
  41: static int nextone;     /* index of next buffer to use */
  42: static int current;     /* index of buffer in use */
  43: 
  44:             /* control flags for crlf conversions */
  45: int newline = 0;        /* fillbuf: in middle of newline expansion */
  46: int prevchar = -1;      /* putbuf: previous char (cr check) */
  47: 
  48: struct tftphdr *rw_init();
  49: 
  50: struct tftphdr *w_init() { return rw_init(0); }         /* write-behind */
  51: struct tftphdr *r_init() { return rw_init(1); }         /* read-ahead */
  52: 
  53: struct tftphdr *
  54: rw_init(x)              /* init for either read-ahead or write-behind */
  55: int x;                  /* zero for write-behind, one for read-head */
  56: {
  57:     newline = 0;            /* init crlf flag */
  58:     prevchar = -1;
  59:     bfs[0].counter =  BF_ALLOC;     /* pass out the first buffer */
  60:     current = 0;
  61:     bfs[1].counter = BF_FREE;
  62:     nextone = x;                    /* ahead or behind? */
  63:     return (struct tftphdr *)bfs[0].buf;
  64: }
  65: 
  66: 
  67: /* Have emptied current buffer by sending to net and getting ack.
  68:    Free it and return next buffer filled with data.
  69:  */
  70: readit(file, dpp, convert)
  71:     FILE *file;                     /* file opened for read */
  72:     struct tftphdr **dpp;
  73:     int convert;                    /* if true, convert to ascii */
  74: {
  75:     struct bf *b;
  76: 
  77:     bfs[current].counter = BF_FREE; /* free old one */
  78:     current = !current;             /* "incr" current */
  79: 
  80:     b = &bfs[current];              /* look at new buffer */
  81:     if (b->counter == BF_FREE)      /* if it's empty */
  82:         read_ahead(file, convert);      /* fill it */
  83: /*      assert(b->counter != BF_FREE);  /* check */
  84:     *dpp = (struct tftphdr *)b->buf;        /* set caller's ptr */
  85:     return b->counter;
  86: }
  87: 
  88: /*
  89:  * fill the input buffer, doing ascii conversions if requested
  90:  * conversions are  lf -> cr,lf  and cr -> cr, nul
  91:  */
  92: read_ahead(file, convert)
  93:     FILE *file;                     /* file opened for read */
  94:     int convert;                    /* if true, convert to ascii */
  95: {
  96:     register int i;
  97:     register char *p;
  98:     register int c;
  99:     struct bf *b;
 100:     struct tftphdr *dp;
 101: 
 102:     b = &bfs[nextone];              /* look at "next" buffer */
 103:     if (b->counter != BF_FREE)      /* nop if not free */
 104:         return;
 105:     nextone = !nextone;             /* "incr" next buffer ptr */
 106: 
 107:     dp = (struct tftphdr *)b->buf;
 108: 
 109:     if (convert == 0) {
 110:         b->counter = read(fileno(file), dp->th_data, SEGSIZE);
 111:         return;
 112:     }
 113: 
 114:     p = dp->th_data;
 115:     for (i = 0 ; i < SEGSIZE; i++) {
 116:         if (newline) {
 117:             if (prevchar == '\n')
 118:                 c = '\n';       /* lf to cr,lf */
 119:             else    c = '\0';       /* cr to cr,nul */
 120:             newline = 0;
 121:         }
 122:         else {
 123:             c = getc(file);
 124:             if (c == EOF) break;
 125:             if (c == '\n' || c == '\r') {
 126:                 prevchar = c;
 127:                 c = '\r';
 128:                 newline = 1;
 129:             }
 130:         }
 131:            *p++ = c;
 132:     }
 133:     b->counter = (int)(p - dp->th_data);
 134: }
 135: 
 136: /* Update count associated with the buffer, get new buffer
 137:    from the queue.  Calls write_behind only if next buffer not
 138:    available.
 139:  */
 140: writeit(file, dpp, ct, convert)
 141:     FILE *file;
 142:     struct tftphdr **dpp;
 143:     int convert;
 144: {
 145:     bfs[current].counter = ct;      /* set size of data to write */
 146:     current = !current;             /* switch to other buffer */
 147:     if (bfs[current].counter != BF_FREE)     /* if not free */
 148:         write_behind(file, convert);     /* flush it */
 149:     bfs[current].counter = BF_ALLOC;        /* mark as alloc'd */
 150:     *dpp =  (struct tftphdr *)bfs[current].buf;
 151:     return ct;                      /* this is a lie of course */
 152: }
 153: 
 154: /*
 155:  * Output a buffer to a file, converting from netascii if requested.
 156:  * CR,NUL -> CR  and CR,LF => LF.
 157:  * Note spec is undefined if we get CR as last byte of file or a
 158:  * CR followed by anything else.  In this case we leave it alone.
 159:  */
 160: write_behind(file, convert)
 161:     FILE *file;
 162:     int convert;
 163: {
 164:     char *buf;
 165:     int count;
 166:     register int ct;
 167:     register char *p;
 168:     register int c;                 /* current character */
 169:     struct bf *b;
 170:     struct tftphdr *dp;
 171: 
 172:     b = &bfs[nextone];
 173:     if (b->counter < -1)            /* anything to flush? */
 174:         return 0;               /* just nop if nothing to do */
 175: 
 176:     count = b->counter;             /* remember byte count */
 177:     b->counter = BF_FREE;           /* reset flag */
 178:     dp = (struct tftphdr *)b->buf;
 179:     nextone = !nextone;             /* incr for next time */
 180:     buf = dp->th_data;
 181: 
 182:     if (count <= 0) return -1;      /* nak logic? */
 183: 
 184:     if (convert == 0)
 185:         return write(fileno(file), buf, count);
 186: 
 187:     p = buf;
 188:     ct = count;
 189:     while (ct--) {                  /* loop over the buffer */
 190:         c = *p++;                   /* pick up a character */
 191:         if (prevchar == '\r') {     /* if prev char was cr */
 192:         if (c == '\n')          /* if have cr,lf then just */
 193:            fseek(file, -1, 1);  /* smash lf on top of the cr */
 194:         else
 195:            if (c == '\0')       /* if have cr,nul then */
 196:             goto skipit;    /* just skip over the putc */
 197:         /* else just fall through and allow it */
 198:         }
 199:         putc(c, file);
 200: skipit:
 201:         prevchar = c;
 202:     }
 203:     return count;
 204: }
 205: 
 206: 
 207: /* When an error has occurred, it is possible that the two sides
 208:  * are out of synch.  Ie: that what I think is the other side's
 209:  * response to packet N is really their response to packet N-1.
 210:  *
 211:  * So, to try to prevent that, we flush all the input queued up
 212:  * for us on the network connection on our host.
 213:  *
 214:  * We return the number of packets we flushed (mostly for reporting
 215:  * when trace is active).
 216:  */
 217: 
 218: int
 219: synchnet(f)
 220: int f;      /* socket to flush */
 221: {
 222:     int i, j = 0;
 223:     char rbuf[PKTSIZE];
 224:     struct sockaddr_in from;
 225:     int fromlen;
 226: 
 227:     while (1) {
 228:         (void) ioctl(f, FIONREAD, &i);
 229:         if (i) {
 230:             j++;
 231:             fromlen = sizeof from;
 232:             (void) recvfrom(f, rbuf, sizeof (rbuf), 0,
 233:                 (caddr_t)&from, &fromlen);
 234:         } else {
 235:             return(j);
 236:         }
 237:     }
 238: }

Defined functions

r_init defined in line 51; used 2 times
read_ahead defined in line 92; used 2 times
readit defined in line 70; used 1 times
rw_init defined in line 53; used 3 times
synchnet defined in line 218; used 2 times
w_init defined in line 50; used 2 times
write_behind defined in line 160; used 3 times
writeit defined in line 140; used 1 times

Defined variables

bfs defined in line 34; used 11 times
current defined in line 42; used 11 times
newline defined in line 45; used 4 times
nextone defined in line 41; used 7 times
prevchar defined in line 46; used 5 times
sccsid defined in line 8; never used

Defined struct's

bf defined in line 31; used 6 times

Defined macros

BF_ALLOC defined in line 37; used 2 times
BF_FREE defined in line 38; used 6 times
PKTSIZE defined in line 29; used 2 times
Last modified: 1986-02-08
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 1330
Valid CSS Valid XHTML 1.0 Strict