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

Defined functions

r_init defined in line 64; used 2 times
read_ahead defined in line 105; used 2 times
readit defined in line 83; used 1 times
rw_init defined in line 66; used 3 times
synchnet defined in line 231; used 2 times
w_init defined in line 63; used 2 times
write_behind defined in line 173; used 3 times
writeit defined in line 153; used 1 times

Defined variables

bfs defined in line 47; used 11 times
current defined in line 55; used 11 times
newline defined in line 58; used 4 times
nextone defined in line 54; used 7 times
prevchar defined in line 59; used 5 times
sccsid defined in line 21; never used

Defined struct's

bf defined in line 44; used 6 times

Defined macros

BF_ALLOC defined in line 50; used 2 times
BF_FREE defined in line 51; used 6 times
PKTSIZE defined in line 42; used 2 times
Last modified: 1991-05-16
Generated: 2016-12-26
Generated by src2html V0.67
page hit count: 3448
Valid CSS Valid XHTML 1.0 Strict