GCC Code Coverage Report
Directory: ./ Exec Total Coverage
File: usr.bin/tftp/tftpsubs.c Lines: 0 74 0.0 %
Date: 2017-11-07 Branches: 0 44 0.0 %

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