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: }