|
|
1.1 ! root 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: }
This archive runs on limited infrastructure. Preserving old code on modern bandwidth. Automated agents are requested to crawl responsibly.