154359Sroberto#ifdef HAVE_CONFIG_H
254359Sroberto# include <config.h>
354359Sroberto#endif
454359Sroberto
554359Sroberto#include <stdio.h>
6285612Sdelphij
7285612Sdelphij#include "ntp_assert.h"
882498Sroberto#include "ntp_syslog.h"
954359Sroberto#include "ntp_stdlib.h"
10285612Sdelphij#include "ntp_lists.h"
1154359Sroberto#include "recvbuff.h"
1254359Sroberto#include "iosignal.h"
1354359Sroberto
14285612Sdelphij
1554359Sroberto/*
1654359Sroberto * Memory allocation
1754359Sroberto */
18285612Sdelphijstatic u_long volatile full_recvbufs;	/* recvbufs on full_recv_fifo */
19285612Sdelphijstatic u_long volatile free_recvbufs;	/* recvbufs on free_recv_list */
20182007Srobertostatic u_long volatile total_recvbufs;	/* total recvbufs currently in use */
2154359Srobertostatic u_long volatile lowater_adds;	/* number of times we have added memory */
22182007Srobertostatic u_long volatile buffer_shortfall;/* number of missed free receive buffers
23285612Sdelphij					   between replenishments */
2454359Sroberto
25285612Sdelphijstatic DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo;
26285612Sdelphijstatic recvbuf_t *		   free_recv_list;
2754359Sroberto
28182007Sroberto#if defined(SYS_WINNT)
29182007Sroberto
30182007Sroberto/*
31182007Sroberto * For Windows we need to set up a lock to manipulate the
32182007Sroberto * recv buffers to prevent corruption. We keep it lock for as
33182007Sroberto * short a time as possible
34182007Sroberto */
35182007Srobertostatic CRITICAL_SECTION RecvLock;
36182007Sroberto# define LOCK()		EnterCriticalSection(&RecvLock)
37182007Sroberto# define UNLOCK()	LeaveCriticalSection(&RecvLock)
3854359Sroberto#else
39285612Sdelphij# define LOCK()		do {} while (FALSE)
40285612Sdelphij# define UNLOCK()	do {} while (FALSE)
4154359Sroberto#endif
4254359Sroberto
43285612Sdelphij#ifdef DEBUG
44285612Sdelphijstatic void uninit_recvbuff(void);
45285612Sdelphij#endif
46285612Sdelphij
47285612Sdelphij
4854359Srobertou_long
4954359Srobertofree_recvbuffs (void)
5054359Sroberto{
5154359Sroberto	return free_recvbufs;
5254359Sroberto}
5354359Sroberto
5454359Srobertou_long
5554359Srobertofull_recvbuffs (void)
5654359Sroberto{
57182007Sroberto	return full_recvbufs;
5854359Sroberto}
5954359Sroberto
6054359Srobertou_long
6154359Srobertototal_recvbuffs (void)
6254359Sroberto{
63182007Sroberto	return total_recvbufs;
6454359Sroberto}
6554359Sroberto
6654359Srobertou_long
6754359Srobertolowater_additions(void)
6854359Sroberto{
6954359Sroberto	return lowater_adds;
7054359Sroberto}
7154359Sroberto
72285612Sdelphijstatic inline void
73182007Srobertoinitialise_buffer(recvbuf_t *buff)
7454359Sroberto{
75285612Sdelphij	ZERO(*buff);
7654359Sroberto}
7754359Sroberto
7854359Srobertostatic void
79182007Srobertocreate_buffers(int nbufs)
8054359Sroberto{
81182007Sroberto	register recvbuf_t *bufp;
82182007Sroberto	int i, abuf;
83182007Sroberto
84182007Sroberto	abuf = nbufs + buffer_shortfall;
85182007Sroberto	buffer_shortfall = 0;
86182007Sroberto
87285612Sdelphij#ifndef DEBUG
88316069Sdelphij	bufp = eallocarray(abuf, sizeof(*bufp));
89285612Sdelphij#endif
90182007Sroberto
91285612Sdelphij	for (i = 0; i < abuf; i++) {
92285612Sdelphij#ifdef DEBUG
93285612Sdelphij		/*
94285612Sdelphij		 * Allocate each buffer individually so they can be
95285612Sdelphij		 * free()d during ntpd shutdown on DEBUG builds to
96285612Sdelphij		 * keep them out of heap leak reports.
97285612Sdelphij		 */
98285612Sdelphij		bufp = emalloc_zero(sizeof(*bufp));
99285612Sdelphij#endif
100285612Sdelphij		LINK_SLIST(free_recv_list, bufp, link);
101182007Sroberto		bufp++;
102182007Sroberto		free_recvbufs++;
103182007Sroberto		total_recvbufs++;
10454359Sroberto	}
10554359Sroberto	lowater_adds++;
10654359Sroberto}
10754359Sroberto
10854359Srobertovoid
10954359Srobertoinit_recvbuff(int nbufs)
11054359Sroberto{
11154359Sroberto
11254359Sroberto	/*
11354359Sroberto	 * Init buffer free list and stat counters
11454359Sroberto	 */
115182007Sroberto	free_recvbufs = total_recvbufs = 0;
116182007Sroberto	full_recvbufs = lowater_adds = 0;
11754359Sroberto
118182007Sroberto	create_buffers(nbufs);
11954359Sroberto
120182007Sroberto#if defined(SYS_WINNT)
121182007Sroberto	InitializeCriticalSection(&RecvLock);
12254359Sroberto#endif
12354359Sroberto
124285612Sdelphij#ifdef DEBUG
125285612Sdelphij	atexit(&uninit_recvbuff);
126285612Sdelphij#endif
12754359Sroberto}
12854359Sroberto
129285612Sdelphij
130285612Sdelphij#ifdef DEBUG
131285612Sdelphijstatic void
132285612Sdelphijuninit_recvbuff(void)
133285612Sdelphij{
134285612Sdelphij	recvbuf_t *rbunlinked;
135285612Sdelphij
136285612Sdelphij	for (;;) {
137285612Sdelphij		UNLINK_FIFO(rbunlinked, full_recv_fifo, link);
138285612Sdelphij		if (rbunlinked == NULL)
139285612Sdelphij			break;
140285612Sdelphij		free(rbunlinked);
141285612Sdelphij	}
142285612Sdelphij
143285612Sdelphij	for (;;) {
144285612Sdelphij		UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link);
145285612Sdelphij		if (rbunlinked == NULL)
146285612Sdelphij			break;
147285612Sdelphij		free(rbunlinked);
148285612Sdelphij	}
149285612Sdelphij}
150285612Sdelphij#endif	/* DEBUG */
151285612Sdelphij
152285612Sdelphij
15354359Sroberto/*
154182007Sroberto * freerecvbuf - make a single recvbuf available for reuse
15554359Sroberto */
156182007Srobertovoid
157182007Srobertofreerecvbuf(recvbuf_t *rb)
15854359Sroberto{
159298699Sdelphij	if (rb) {
160298699Sdelphij		LOCK();
161298699Sdelphij		rb->used--;
162298699Sdelphij		if (rb->used != 0)
163298699Sdelphij			msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
164298699Sdelphij		LINK_SLIST(free_recv_list, rb, link);
165298699Sdelphij		free_recvbufs++;
166298699Sdelphij		UNLOCK();
16754359Sroberto	}
16854359Sroberto}
16954359Sroberto
170182007Sroberto
17154359Srobertovoid
172182007Srobertoadd_full_recv_buffer(recvbuf_t *rb)
17354359Sroberto{
174182007Sroberto	if (rb == NULL) {
175182007Sroberto		msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
176182007Sroberto		return;
177182007Sroberto	}
178182007Sroberto	LOCK();
179285612Sdelphij	LINK_FIFO(full_recv_fifo, rb, link);
180182007Sroberto	full_recvbufs++;
181182007Sroberto	UNLOCK();
18254359Sroberto}
18354359Sroberto
184285612Sdelphij
185182007Srobertorecvbuf_t *
186182007Srobertoget_free_recv_buffer(void)
18754359Sroberto{
188285612Sdelphij	recvbuf_t *buffer;
189285612Sdelphij
190182007Sroberto	LOCK();
191285612Sdelphij	UNLINK_HEAD_SLIST(buffer, free_recv_list, link);
192285612Sdelphij	if (buffer != NULL) {
193182007Sroberto		free_recvbufs--;
194182007Sroberto		initialise_buffer(buffer);
195285612Sdelphij		buffer->used++;
196285612Sdelphij	} else {
197182007Sroberto		buffer_shortfall++;
19854359Sroberto	}
199182007Sroberto	UNLOCK();
200285612Sdelphij
201285612Sdelphij	return buffer;
20254359Sroberto}
20354359Sroberto
204285612Sdelphij
205182007Sroberto#ifdef HAVE_IO_COMPLETION_PORT
206182007Srobertorecvbuf_t *
207182007Srobertoget_free_recv_buffer_alloc(void)
20854359Sroberto{
209285612Sdelphij	recvbuf_t *buffer;
210285612Sdelphij
211285612Sdelphij	buffer = get_free_recv_buffer();
212285612Sdelphij	if (NULL == buffer) {
213182007Sroberto		create_buffers(RECV_INC);
214182007Sroberto		buffer = get_free_recv_buffer();
21554359Sroberto	}
216289997Sglebius	ENSURE(buffer != NULL);
217182007Sroberto	return (buffer);
21854359Sroberto}
219182007Sroberto#endif
22054359Sroberto
221285612Sdelphij
222182007Srobertorecvbuf_t *
22354359Srobertoget_full_recv_buffer(void)
22454359Sroberto{
225285612Sdelphij	recvbuf_t *	rbuf;
226285612Sdelphij
227182007Sroberto	LOCK();
228182007Sroberto
229182007Sroberto#ifdef HAVE_SIGNALED_IO
230182007Sroberto	/*
231182007Sroberto	 * make sure there are free buffers when we
232285612Sdelphij	 * wander off to do lengthy packet processing with
233182007Sroberto	 * any buffer we grab from the full list.
234182007Sroberto	 *
235182007Sroberto	 * fixes malloc() interrupted by SIGIO risk
236182007Sroberto	 * (Bug 889)
237182007Sroberto	 */
238285612Sdelphij	if (NULL == free_recv_list || buffer_shortfall > 0) {
239182007Sroberto		/*
240182007Sroberto		 * try to get us some more buffers
241182007Sroberto		 */
242182007Sroberto		create_buffers(RECV_INC);
243182007Sroberto	}
244182007Sroberto#endif
245182007Sroberto
246182007Sroberto	/*
247182007Sroberto	 * try to grab a full buffer
248182007Sroberto	 */
249285612Sdelphij	UNLINK_FIFO(rbuf, full_recv_fifo, link);
250182007Sroberto	if (rbuf != NULL)
251285612Sdelphij		full_recvbufs--;
252285612Sdelphij	UNLOCK();
253285612Sdelphij
254285612Sdelphij	return rbuf;
255285612Sdelphij}
256285612Sdelphij
257285612Sdelphij
258285612Sdelphij/*
259285612Sdelphij * purge_recv_buffers_for_fd() - purges any previously-received input
260285612Sdelphij *				 from a given file descriptor.
261285612Sdelphij */
262285612Sdelphijvoid
263285612Sdelphijpurge_recv_buffers_for_fd(
264298699Sdelphij	int	fd
265285612Sdelphij	)
266285612Sdelphij{
267285612Sdelphij	recvbuf_t *rbufp;
268285612Sdelphij	recvbuf_t *next;
269285612Sdelphij	recvbuf_t *punlinked;
270285612Sdelphij
271285612Sdelphij	LOCK();
272285612Sdelphij
273285612Sdelphij	for (rbufp = HEAD_FIFO(full_recv_fifo);
274285612Sdelphij	     rbufp != NULL;
275285612Sdelphij	     rbufp = next) {
276285612Sdelphij		next = rbufp->link;
277298699Sdelphij#	    ifdef HAVE_IO_COMPLETION_PORT
278298699Sdelphij		if (rbufp->dstadr == NULL && rbufp->fd == fd)
279298699Sdelphij#	    else
280298699Sdelphij		if (rbufp->fd == fd)
281298699Sdelphij#	    endif
282298699Sdelphij		{
283285612Sdelphij			UNLINK_MID_FIFO(punlinked, full_recv_fifo,
284285612Sdelphij					rbufp, link, recvbuf_t);
285285612Sdelphij			INSIST(punlinked == rbufp);
286285612Sdelphij			full_recvbufs--;
287285612Sdelphij			freerecvbuf(rbufp);
288285612Sdelphij		}
28954359Sroberto	}
290285612Sdelphij
291182007Sroberto	UNLOCK();
29254359Sroberto}
293182007Sroberto
294285612Sdelphij
295182007Sroberto/*
296182007Sroberto * Checks to see if there are buffers to process
297182007Sroberto */
298182007Srobertoisc_boolean_t has_full_recv_buffer(void)
299182007Sroberto{
300285612Sdelphij	if (HEAD_FIFO(full_recv_fifo) != NULL)
301182007Sroberto		return (ISC_TRUE);
302182007Sroberto	else
303182007Sroberto		return (ISC_FALSE);
304182007Sroberto}
305285612Sdelphij
306285612Sdelphij
307285612Sdelphij#ifdef NTP_DEBUG_LISTS_H
308285612Sdelphijvoid
309285612Sdelphijcheck_gen_fifo_consistency(void *fifo)
310285612Sdelphij{
311285612Sdelphij	gen_fifo *pf;
312285612Sdelphij	gen_node *pthis;
313285612Sdelphij	gen_node **pptail;
314285612Sdelphij
315285612Sdelphij	pf = fifo;
316285612Sdelphij	REQUIRE((NULL == pf->phead && NULL == pf->pptail) ||
317285612Sdelphij		(NULL != pf->phead && NULL != pf->pptail));
318285612Sdelphij
319285612Sdelphij	pptail = &pf->phead;
320285612Sdelphij	for (pthis = pf->phead;
321285612Sdelphij	     pthis != NULL;
322285612Sdelphij	     pthis = pthis->link)
323285612Sdelphij		if (NULL != pthis->link)
324285612Sdelphij			pptail = &pthis->link;
325285612Sdelphij
326285612Sdelphij	REQUIRE(NULL == pf->pptail || pptail == pf->pptail);
327285612Sdelphij}
328285612Sdelphij#endif	/* NTP_DEBUG_LISTS_H */
329