2 * Copyright (c) 1983, 1993
3 * The Regents of the University of California. All rights reserved.
5 * Redistribution and use in source and binary forms, with or without
6 * modification, are permitted provided that the following conditions
8 * 1. Redistributions of source code must retain the above copyright
9 * notice, this list of conditions and the following disclaimer.
10 * 2. Redistributions in binary form must reproduce the above copyright
11 * notice, this list of conditions and the following disclaimer in the
12 * documentation and/or other materials provided with the distribution.
13 * 3. All advertising materials mentioning features or use of this software
14 * must display the following acknowledgement:
15 * This product includes software developed by the University of
16 * California, Berkeley and its contributors.
17 * 4. Neither the name of the University nor the names of its contributors
18 * may be used to endorse or promote products derived from this software
19 * without specific prior written permission.
21 * THIS SOFTWARE IS PROVIDED BY THE REGENTS AND CONTRIBUTORS ``AS IS'' AND
22 * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED TO, THE
23 * IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE
24 * ARE DISCLAIMED. IN NO EVENT SHALL THE REGENTS OR CONTRIBUTORS BE LIABLE
25 * FOR ANY DIRECT, INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
26 * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS
27 * OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION)
28 * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, STRICT
29 * LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY
30 * OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
36 /* Simple minded read-ahead/write-behind subroutines for tftp user and
37 server. Written originally with multiple buffers in mind, but current
38 implementation has two buffer logic wired in.
40 Todo: add some sort of final error check so when the write-buffer
41 is finally flushed, the caller can detect if the disk filled up
42 (or had an i/o error) and return a nak to the other side.
47 #include <sys/ioctl.h>
49 #define PKTSIZE MAX_SEGSIZE+4 /* should be moved to tftp.h */
51 int segsize
= SEGSIZE
; /* Default segsize */
54 int counter
; /* size of data in buffer, or flag */
55 char buf
[PKTSIZE
]; /* room for data packet */
58 /* Values for bf.counter */
59 #define BF_ALLOC -3 /* alloc'd but not yet filled */
60 #define BF_FREE -2 /* free */
61 /* [-1 .. segsize] = size of data in the data buffer */
63 static int nextone
; /* index of next buffer to use */
64 static int current
; /* index of buffer in use */
66 /* control flags for crlf conversions */
67 int newline
= 0; /* fillbuf: in middle of newline expansion */
68 int prevchar
= -1; /* putbuf: previous char (cr check) */
70 static struct tftphdr
*rw_init(int);
72 struct tftphdr
*w_init()
77 struct tftphdr
*r_init()
82 /* init for either read-ahead or write-behind */
83 /* x == zero for write-behind, one for read-head */
84 static struct tftphdr
*rw_init(int x
)
86 newline
= 0; /* init crlf flag */
88 bfs
[0].counter
= BF_ALLOC
; /* pass out the first buffer */
90 bfs
[1].counter
= BF_FREE
;
91 nextone
= x
; /* ahead or behind? */
92 return (struct tftphdr
*)bfs
[0].buf
;
95 /* Have emptied current buffer by sending to net and getting ack.
96 Free it and return next buffer filled with data.
98 int readit(FILE * file
, struct tftphdr
**dpp
, int convert
)
102 bfs
[current
].counter
= BF_FREE
; /* free old one */
103 current
= !current
; /* "incr" current */
105 b
= &bfs
[current
]; /* look at new buffer */
106 if (b
->counter
== BF_FREE
) /* if it's empty */
107 read_ahead(file
, convert
); /* fill it */
108 /* assert(b->counter != BF_FREE);*//* check */
109 *dpp
= (struct tftphdr
*)b
->buf
; /* set caller's ptr */
114 * fill the input buffer, doing ascii conversions if requested
115 * conversions are lf -> cr,lf and cr -> cr, nul
117 void read_ahead(FILE * file
, int convert
)
125 b
= &bfs
[nextone
]; /* look at "next" buffer */
126 if (b
->counter
!= BF_FREE
) /* nop if not free */
128 nextone
= !nextone
; /* "incr" next buffer ptr */
130 dp
= (struct tftphdr
*)b
->buf
;
133 b
->counter
= read(fileno(file
), dp
->th_data
, segsize
);
138 for (i
= 0; i
< segsize
; i
++) {
140 if (prevchar
== '\n')
141 c
= '\n'; /* lf to cr,lf */
143 c
= '\0'; /* cr to cr,nul */
149 if (c
== '\n' || c
== '\r') {
157 b
->counter
= (int)(p
- dp
->th_data
);
160 /* Update count associated with the buffer, get new buffer
161 from the queue. Calls write_behind only if next buffer not
164 int writeit(FILE * file
, struct tftphdr
**dpp
, int ct
, int convert
)
166 bfs
[current
].counter
= ct
; /* set size of data to write */
167 current
= !current
; /* switch to other buffer */
168 if (bfs
[current
].counter
!= BF_FREE
) /* if not free */
169 (void)write_behind(file
, convert
); /* flush it */
170 bfs
[current
].counter
= BF_ALLOC
; /* mark as alloc'd */
171 *dpp
= (struct tftphdr
*)bfs
[current
].buf
;
172 return ct
; /* this is a lie of course */
176 * Output a buffer to a file, converting from netascii if requested.
177 * CR,NUL -> CR and CR,LF => LF.
178 * Note spec is undefined if we get CR as last byte of file or a
179 * CR followed by anything else. In this case we leave it alone.
181 int write_behind(FILE * file
, int convert
)
187 int c
; /* current character */
192 if (b
->counter
< -1) /* anything to flush? */
193 return 0; /* just nop if nothing to do */
195 count
= b
->counter
; /* remember byte count */
196 b
->counter
= BF_FREE
; /* reset flag */
197 dp
= (struct tftphdr
*)b
->buf
;
198 nextone
= !nextone
; /* incr for next time */
202 return -1; /* nak logic? */
205 return write(fileno(file
), buf
, count
);
209 while (ct
--) { /* loop over the buffer */
210 c
= *p
++; /* pick up a character */
211 if (prevchar
== '\r') { /* if prev char was cr */
212 if (c
== '\n') /* if have cr,lf then just */
213 fseek(file
, -1, 1); /* smash lf on top of the cr */
214 else if (c
== '\0') /* if have cr,nul then */
215 goto skipit
; /* just skip over the putc */
216 /* else just fall through and allow it */
225 /* When an error has occurred, it is possible that the two sides
226 * are out of synch. Ie: that what I think is the other side's
227 * response to packet N is really their response to packet N-1.
229 * So, to try to prevent that, we flush all the input queued up
230 * for us on the network connection on our host.
232 * We return the number of packets we flushed (mostly for reporting
233 * when trace is active).
237 { /* socket to flush */
240 union sock_addr from
;
243 struct timeval notime
;
246 notime
.tv_sec
= notime
.tv_usec
= 0;
249 FD_SET(f
, &socketset
);
251 if (select(f
, &socketset
, NULL
, NULL
, ¬ime
) <= 0)
252 break; /* Nothing to read */
254 /* Otherwise drain the packet */
256 fromlen
= sizeof(from
);
257 (void)recvfrom(f
, rbuf
, sizeof(rbuf
), 0,
261 return pktcount
; /* Return packets drained */
264 int pick_port_bind(int sockfd
, union sock_addr
*myaddr
,
265 unsigned int port_range_from
,
266 unsigned int port_range_to
)
268 unsigned int port
, firstport
;
271 if (port_range_from
!= 0 && port_range_to
!= 0) {
275 firstport
= port_range
276 ? port_range_from
+ rand() % (port_range_to
- port_range_from
+ 1)
282 sa_set_port(myaddr
, htons(port
));
283 if (bind(sockfd
, &myaddr
->sa
, SOCKLEN(myaddr
)) < 0) {
284 /* Some versions of Linux return EINVAL instead of EADDRINUSE */
285 if (!(port_range
&& (errno
== EINVAL
|| errno
== EADDRINUSE
)))
288 /* Normally, we shouldn't have to loop, but some situations involving
289 aborted transfers make it possible. */
295 if (port
> port_range_to
)
296 port
= port_range_from
;
297 } while (port
!= firstport
);
303 set_sock_addr(char *host
,union sock_addr
*s
, char **name
)
305 struct addrinfo
*addrResult
;
306 struct addrinfo hints
;
309 memset(&hints
, 0, sizeof(hints
));
310 hints
.ai_family
= s
->sa
.sa_family
;
311 hints
.ai_flags
= AI_CANONNAME
| AI_ADDRCONFIG
;
312 hints
.ai_socktype
= SOCK_DGRAM
;
313 hints
.ai_protocol
= IPPROTO_UDP
;
314 err
= getaddrinfo(strip_address(host
), NULL
, &hints
, &addrResult
);
317 if (addrResult
== NULL
)
319 memcpy(s
, addrResult
->ai_addr
, addrResult
->ai_addrlen
);
321 if (addrResult
->ai_canonname
)
322 *name
= xstrdup(addrResult
->ai_canonname
);
324 *name
= xstrdup(host
);
326 freeaddrinfo(addrResult
);
331 int is_numeric_ipv6(const char *p
)
333 /* A numeric IPv6 address consist at least of 2 ':' and
334 * it may have sequences of hex-digits and maybe contain
335 * a '.' from a IPv4 mapped address and maybe is enclosed in []
336 * we do not check here, if it is a valid IPv6 address
337 * only if is something like a numeric IPv6 address or something else
352 while ((c
= *p
++) && c
!= ']') {
360 case '0': case '1': case '2': case '3': case '4':
361 case '5': case '6': case '7': case '8': case '9':
362 case 'A': case 'B': case 'C': case 'D': case 'E': case 'F':
363 case 'a': case 'b': case 'c': case 'd': case 'e': case 'f':
366 return 0; /* Invalid character */
370 if (colon
< 2 || colon
> 7)
374 /* An IPv4-mapped address in dot-quad form will have 3 dots */
377 /* The IPv4-mapped address takes the space of one colon */
382 /* If bracketed, must be closed, and vice versa */
383 if (bracket
^ (c
== ']'))
386 /* Otherwise, assume we're okay */
390 /* strip [] from numeric IPv6 addreses */
392 char *strip_address(char *addr
)
396 if (is_numeric_ipv6(addr
) && (*addr
== '[')) {
397 p
= addr
+ strlen(addr
);