|
|
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.