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