New directory structure.
[unix-history] / usr / src / usr.bin / tftp / tftpsubs.c
CommitLineData
3ef81a10
GM
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
15631344 8static char sccsid[] = "@(#)tftpsubs.c 5.2 (Berkeley) %G%";
3ef81a10
GM
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>
15631344 24#include <sys/ioctl.h>
3ef81a10
GM
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
31struct 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
41static int nextone; /* index of next buffer to use */
42static int current; /* index of buffer in use */
43
44 /* control flags for crlf conversions */
45int newline = 0; /* fillbuf: in middle of newline expansion */
46int prevchar = -1; /* putbuf: previous char (cr check) */
47
48struct tftphdr *rw_init();
49
50struct tftphdr *w_init() { return rw_init(0); } /* write-behind */
51struct tftphdr *r_init() { return rw_init(1); } /* read-ahead */
52
53struct tftphdr *
54rw_init(x) /* init for either read-ahead or write-behind */
55int 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 */
70readit(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 */
92read_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 */
140writeit(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 */
160write_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);
200skipit:
201 prevchar = c;
202 }
203 return count;
204}
205
206
15631344
GM
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
218int
219synchnet(f)
220int 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}