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