xref: /freebsd/contrib/ntp/libntp/recvbuff.c (revision 4990d495fcc77c51b3f46c91ba3a064b565afae0)
1c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
2c0b746e5SOllivier Robert # include <config.h>
3c0b746e5SOllivier Robert #endif
4c0b746e5SOllivier Robert 
5c0b746e5SOllivier Robert #include <stdio.h>
62b15cb3dSCy Schubert 
72b15cb3dSCy Schubert #include "ntp_assert.h"
8c0b746e5SOllivier Robert #include "ntp_syslog.h"
9224ba2bdSOllivier Robert #include "ntp_stdlib.h"
102b15cb3dSCy Schubert #include "ntp_lists.h"
11c0b746e5SOllivier Robert #include "recvbuff.h"
12c0b746e5SOllivier Robert #include "iosignal.h"
13c0b746e5SOllivier Robert 
142b15cb3dSCy Schubert 
15c0b746e5SOllivier Robert /*
16c0b746e5SOllivier Robert  * Memory allocation
17c0b746e5SOllivier Robert  */
182b15cb3dSCy Schubert static u_long volatile full_recvbufs;	/* recvbufs on full_recv_fifo */
192b15cb3dSCy Schubert static u_long volatile free_recvbufs;	/* recvbufs on free_recv_list */
20c0b746e5SOllivier Robert static u_long volatile total_recvbufs;	/* total recvbufs currently in use */
21c0b746e5SOllivier Robert static u_long volatile lowater_adds;	/* number of times we have added memory */
22ea906c41SOllivier Robert static u_long volatile buffer_shortfall;/* number of missed free receive buffers
23ea906c41SOllivier Robert 					   between replenishments */
24c0b746e5SOllivier Robert 
252b15cb3dSCy Schubert static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo;
262b15cb3dSCy Schubert static recvbuf_t *		   free_recv_list;
27c0b746e5SOllivier Robert 
28ea906c41SOllivier Robert #if defined(SYS_WINNT)
29ea906c41SOllivier Robert 
30ea906c41SOllivier Robert /*
31ea906c41SOllivier Robert  * For Windows we need to set up a lock to manipulate the
32ea906c41SOllivier Robert  * recv buffers to prevent corruption. We keep it lock for as
33ea906c41SOllivier Robert  * short a time as possible
34ea906c41SOllivier Robert  */
35ea906c41SOllivier Robert static CRITICAL_SECTION RecvLock;
36ea906c41SOllivier Robert # define LOCK()		EnterCriticalSection(&RecvLock)
37ea906c41SOllivier Robert # define UNLOCK()	LeaveCriticalSection(&RecvLock)
38c0b746e5SOllivier Robert #else
392b15cb3dSCy Schubert # define LOCK()		do {} while (FALSE)
402b15cb3dSCy Schubert # define UNLOCK()	do {} while (FALSE)
41c0b746e5SOllivier Robert #endif
42c0b746e5SOllivier Robert 
432b15cb3dSCy Schubert #ifdef DEBUG
442b15cb3dSCy Schubert static void uninit_recvbuff(void);
452b15cb3dSCy Schubert #endif
462b15cb3dSCy Schubert 
472b15cb3dSCy Schubert 
48c0b746e5SOllivier Robert u_long
49c0b746e5SOllivier Robert free_recvbuffs (void)
50c0b746e5SOllivier Robert {
51c0b746e5SOllivier Robert 	return free_recvbufs;
52c0b746e5SOllivier Robert }
53c0b746e5SOllivier Robert 
54c0b746e5SOllivier Robert u_long
55c0b746e5SOllivier Robert full_recvbuffs (void)
56c0b746e5SOllivier Robert {
57ea906c41SOllivier Robert 	return full_recvbufs;
58c0b746e5SOllivier Robert }
59c0b746e5SOllivier Robert 
60c0b746e5SOllivier Robert u_long
61c0b746e5SOllivier Robert total_recvbuffs (void)
62c0b746e5SOllivier Robert {
63ea906c41SOllivier Robert 	return total_recvbufs;
64c0b746e5SOllivier Robert }
65c0b746e5SOllivier Robert 
66c0b746e5SOllivier Robert u_long
67c0b746e5SOllivier Robert lowater_additions(void)
68c0b746e5SOllivier Robert {
69c0b746e5SOllivier Robert 	return lowater_adds;
70c0b746e5SOllivier Robert }
71c0b746e5SOllivier Robert 
722b15cb3dSCy Schubert static inline void
73ea906c41SOllivier Robert initialise_buffer(recvbuf_t *buff)
74c0b746e5SOllivier Robert {
752b15cb3dSCy Schubert 	ZERO(*buff);
76c0b746e5SOllivier Robert }
77c0b746e5SOllivier Robert 
78c0b746e5SOllivier Robert static void
79ea906c41SOllivier Robert create_buffers(int nbufs)
80c0b746e5SOllivier Robert {
81ea906c41SOllivier Robert 	register recvbuf_t *bufp;
82ea906c41SOllivier Robert 	int i, abuf;
83c0b746e5SOllivier Robert 
84ea906c41SOllivier Robert 	abuf = nbufs + buffer_shortfall;
85ea906c41SOllivier Robert 	buffer_shortfall = 0;
86ea906c41SOllivier Robert 
872b15cb3dSCy Schubert #ifndef DEBUG
882b15cb3dSCy Schubert 	bufp = emalloc_zero(abuf * sizeof(*bufp));
892b15cb3dSCy Schubert #endif
90ea906c41SOllivier Robert 
912b15cb3dSCy Schubert 	for (i = 0; i < abuf; i++) {
922b15cb3dSCy Schubert #ifdef DEBUG
932b15cb3dSCy Schubert 		/*
942b15cb3dSCy Schubert 		 * Allocate each buffer individually so they can be
952b15cb3dSCy Schubert 		 * free()d during ntpd shutdown on DEBUG builds to
962b15cb3dSCy Schubert 		 * keep them out of heap leak reports.
972b15cb3dSCy Schubert 		 */
982b15cb3dSCy Schubert 		bufp = emalloc_zero(sizeof(*bufp));
992b15cb3dSCy Schubert #endif
1002b15cb3dSCy Schubert 		LINK_SLIST(free_recv_list, bufp, link);
101ea906c41SOllivier Robert 		bufp++;
102ea906c41SOllivier Robert 		free_recvbufs++;
103ea906c41SOllivier Robert 		total_recvbufs++;
104ea906c41SOllivier Robert 	}
105c0b746e5SOllivier Robert 	lowater_adds++;
106c0b746e5SOllivier Robert }
107c0b746e5SOllivier Robert 
108c0b746e5SOllivier Robert void
109c0b746e5SOllivier Robert init_recvbuff(int nbufs)
110c0b746e5SOllivier Robert {
111c0b746e5SOllivier Robert 
112c0b746e5SOllivier Robert 	/*
113c0b746e5SOllivier Robert 	 * Init buffer free list and stat counters
114c0b746e5SOllivier Robert 	 */
115ea906c41SOllivier Robert 	free_recvbufs = total_recvbufs = 0;
116c0b746e5SOllivier Robert 	full_recvbufs = lowater_adds = 0;
117c0b746e5SOllivier Robert 
118ea906c41SOllivier Robert 	create_buffers(nbufs);
119ea906c41SOllivier Robert 
120ea906c41SOllivier Robert #if defined(SYS_WINNT)
121ea906c41SOllivier Robert 	InitializeCriticalSection(&RecvLock);
122c0b746e5SOllivier Robert #endif
123c0b746e5SOllivier Robert 
1242b15cb3dSCy Schubert #ifdef DEBUG
1252b15cb3dSCy Schubert 	atexit(&uninit_recvbuff);
1262b15cb3dSCy Schubert #endif
127c0b746e5SOllivier Robert }
128c0b746e5SOllivier Robert 
1292b15cb3dSCy Schubert 
1302b15cb3dSCy Schubert #ifdef DEBUG
1312b15cb3dSCy Schubert static void
1322b15cb3dSCy Schubert uninit_recvbuff(void)
1332b15cb3dSCy Schubert {
1342b15cb3dSCy Schubert 	recvbuf_t *rbunlinked;
1352b15cb3dSCy Schubert 
1362b15cb3dSCy Schubert 	for (;;) {
1372b15cb3dSCy Schubert 		UNLINK_FIFO(rbunlinked, full_recv_fifo, link);
1382b15cb3dSCy Schubert 		if (rbunlinked == NULL)
1392b15cb3dSCy Schubert 			break;
1402b15cb3dSCy Schubert 		free(rbunlinked);
1412b15cb3dSCy Schubert 	}
1422b15cb3dSCy Schubert 
1432b15cb3dSCy Schubert 	for (;;) {
1442b15cb3dSCy Schubert 		UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link);
1452b15cb3dSCy Schubert 		if (rbunlinked == NULL)
1462b15cb3dSCy Schubert 			break;
1472b15cb3dSCy Schubert 		free(rbunlinked);
1482b15cb3dSCy Schubert 	}
1492b15cb3dSCy Schubert }
1502b15cb3dSCy Schubert #endif	/* DEBUG */
1512b15cb3dSCy Schubert 
1522b15cb3dSCy Schubert 
153c0b746e5SOllivier Robert /*
154c0b746e5SOllivier Robert  * freerecvbuf - make a single recvbuf available for reuse
155c0b746e5SOllivier Robert  */
156c0b746e5SOllivier Robert void
157ea906c41SOllivier Robert freerecvbuf(recvbuf_t *rb)
158c0b746e5SOllivier Robert {
159*4990d495SXin LI 	if (rb) {
160ea906c41SOllivier Robert 		LOCK();
1612b15cb3dSCy Schubert 		rb->used--;
162ea906c41SOllivier Robert 		if (rb->used != 0)
163ea906c41SOllivier Robert 			msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
1642b15cb3dSCy Schubert 		LINK_SLIST(free_recv_list, rb, link);
165c0b746e5SOllivier Robert 		free_recvbufs++;
166ea906c41SOllivier Robert 		UNLOCK();
167c0b746e5SOllivier Robert 	}
168*4990d495SXin LI }
169c0b746e5SOllivier Robert 
170c0b746e5SOllivier Robert 
171c0b746e5SOllivier Robert void
172ea906c41SOllivier Robert add_full_recv_buffer(recvbuf_t *rb)
173c0b746e5SOllivier Robert {
174ea906c41SOllivier Robert 	if (rb == NULL) {
175ea906c41SOllivier Robert 		msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
176ea906c41SOllivier Robert 		return;
177c0b746e5SOllivier Robert 	}
178ea906c41SOllivier Robert 	LOCK();
1792b15cb3dSCy Schubert 	LINK_FIFO(full_recv_fifo, rb, link);
180c0b746e5SOllivier Robert 	full_recvbufs++;
181ea906c41SOllivier Robert 	UNLOCK();
182c0b746e5SOllivier Robert }
183c0b746e5SOllivier Robert 
1842b15cb3dSCy Schubert 
185ea906c41SOllivier Robert recvbuf_t *
186c0b746e5SOllivier Robert get_free_recv_buffer(void)
187c0b746e5SOllivier Robert {
1882b15cb3dSCy Schubert 	recvbuf_t *buffer;
1892b15cb3dSCy Schubert 
190ea906c41SOllivier Robert 	LOCK();
1912b15cb3dSCy Schubert 	UNLINK_HEAD_SLIST(buffer, free_recv_list, link);
1922b15cb3dSCy Schubert 	if (buffer != NULL) {
193ea906c41SOllivier Robert 		free_recvbufs--;
194ea906c41SOllivier Robert 		initialise_buffer(buffer);
1952b15cb3dSCy Schubert 		buffer->used++;
1962b15cb3dSCy Schubert 	} else {
197ea906c41SOllivier Robert 		buffer_shortfall++;
198c0b746e5SOllivier Robert 	}
199ea906c41SOllivier Robert 	UNLOCK();
2002b15cb3dSCy Schubert 
2012b15cb3dSCy Schubert 	return buffer;
202c0b746e5SOllivier Robert }
203c0b746e5SOllivier Robert 
2042b15cb3dSCy Schubert 
205ea906c41SOllivier Robert #ifdef HAVE_IO_COMPLETION_PORT
206ea906c41SOllivier Robert recvbuf_t *
207ea906c41SOllivier Robert get_free_recv_buffer_alloc(void)
208c0b746e5SOllivier Robert {
2092b15cb3dSCy Schubert 	recvbuf_t *buffer;
2102b15cb3dSCy Schubert 
2112b15cb3dSCy Schubert 	buffer = get_free_recv_buffer();
2122b15cb3dSCy Schubert 	if (NULL == buffer) {
213ea906c41SOllivier Robert 		create_buffers(RECV_INC);
214ea906c41SOllivier Robert 		buffer = get_free_recv_buffer();
215c0b746e5SOllivier Robert 	}
2169034852cSGleb Smirnoff 	ENSURE(buffer != NULL);
217ea906c41SOllivier Robert 	return (buffer);
218c0b746e5SOllivier Robert }
219ea906c41SOllivier Robert #endif
220c0b746e5SOllivier Robert 
2212b15cb3dSCy Schubert 
222ea906c41SOllivier Robert recvbuf_t *
223c0b746e5SOllivier Robert get_full_recv_buffer(void)
224c0b746e5SOllivier Robert {
225ea906c41SOllivier Robert 	recvbuf_t *	rbuf;
2262b15cb3dSCy Schubert 
227ea906c41SOllivier Robert 	LOCK();
228ea906c41SOllivier Robert 
229ea906c41SOllivier Robert #ifdef HAVE_SIGNALED_IO
230ea906c41SOllivier Robert 	/*
231ea906c41SOllivier Robert 	 * make sure there are free buffers when we
2322b15cb3dSCy Schubert 	 * wander off to do lengthy packet processing with
233ea906c41SOllivier Robert 	 * any buffer we grab from the full list.
234ea906c41SOllivier Robert 	 *
235ea906c41SOllivier Robert 	 * fixes malloc() interrupted by SIGIO risk
236ea906c41SOllivier Robert 	 * (Bug 889)
237ea906c41SOllivier Robert 	 */
2382b15cb3dSCy Schubert 	if (NULL == free_recv_list || buffer_shortfall > 0) {
239ea906c41SOllivier Robert 		/*
240ea906c41SOllivier Robert 		 * try to get us some more buffers
241ea906c41SOllivier Robert 		 */
242ea906c41SOllivier Robert 		create_buffers(RECV_INC);
243c0b746e5SOllivier Robert 	}
244ea906c41SOllivier Robert #endif
245ea906c41SOllivier Robert 
246ea906c41SOllivier Robert 	/*
247ea906c41SOllivier Robert 	 * try to grab a full buffer
248ea906c41SOllivier Robert 	 */
2492b15cb3dSCy Schubert 	UNLINK_FIFO(rbuf, full_recv_fifo, link);
250ea906c41SOllivier Robert 	if (rbuf != NULL)
2512b15cb3dSCy Schubert 		full_recvbufs--;
252ea906c41SOllivier Robert 	UNLOCK();
2532b15cb3dSCy Schubert 
2542b15cb3dSCy Schubert 	return rbuf;
255ea906c41SOllivier Robert }
256ea906c41SOllivier Robert 
2572b15cb3dSCy Schubert 
2582b15cb3dSCy Schubert /*
2592b15cb3dSCy Schubert  * purge_recv_buffers_for_fd() - purges any previously-received input
2602b15cb3dSCy Schubert  *				 from a given file descriptor.
2612b15cb3dSCy Schubert  */
2622b15cb3dSCy Schubert void
2632b15cb3dSCy Schubert purge_recv_buffers_for_fd(
264*4990d495SXin LI 	int	fd
2652b15cb3dSCy Schubert 	)
2662b15cb3dSCy Schubert {
2672b15cb3dSCy Schubert 	recvbuf_t *rbufp;
2682b15cb3dSCy Schubert 	recvbuf_t *next;
2692b15cb3dSCy Schubert 	recvbuf_t *punlinked;
2702b15cb3dSCy Schubert 
2712b15cb3dSCy Schubert 	LOCK();
2722b15cb3dSCy Schubert 
2732b15cb3dSCy Schubert 	for (rbufp = HEAD_FIFO(full_recv_fifo);
2742b15cb3dSCy Schubert 	     rbufp != NULL;
2752b15cb3dSCy Schubert 	     rbufp = next) {
2762b15cb3dSCy Schubert 		next = rbufp->link;
277*4990d495SXin LI #	    ifdef HAVE_IO_COMPLETION_PORT
278*4990d495SXin LI 		if (rbufp->dstadr == NULL && rbufp->fd == fd)
279*4990d495SXin LI #	    else
280*4990d495SXin LI 		if (rbufp->fd == fd)
281*4990d495SXin LI #	    endif
282*4990d495SXin LI 		{
2832b15cb3dSCy Schubert 			UNLINK_MID_FIFO(punlinked, full_recv_fifo,
2842b15cb3dSCy Schubert 					rbufp, link, recvbuf_t);
2852b15cb3dSCy Schubert 			INSIST(punlinked == rbufp);
2862b15cb3dSCy Schubert 			full_recvbufs--;
2872b15cb3dSCy Schubert 			freerecvbuf(rbufp);
2882b15cb3dSCy Schubert 		}
2892b15cb3dSCy Schubert 	}
2902b15cb3dSCy Schubert 
2912b15cb3dSCy Schubert 	UNLOCK();
2922b15cb3dSCy Schubert }
2932b15cb3dSCy Schubert 
2942b15cb3dSCy Schubert 
295ea906c41SOllivier Robert /*
296ea906c41SOllivier Robert  * Checks to see if there are buffers to process
297ea906c41SOllivier Robert  */
298ea906c41SOllivier Robert isc_boolean_t has_full_recv_buffer(void)
299ea906c41SOllivier Robert {
3002b15cb3dSCy Schubert 	if (HEAD_FIFO(full_recv_fifo) != NULL)
301ea906c41SOllivier Robert 		return (ISC_TRUE);
302ea906c41SOllivier Robert 	else
303ea906c41SOllivier Robert 		return (ISC_FALSE);
304c0b746e5SOllivier Robert }
3052b15cb3dSCy Schubert 
3062b15cb3dSCy Schubert 
3072b15cb3dSCy Schubert #ifdef NTP_DEBUG_LISTS_H
3082b15cb3dSCy Schubert void
3092b15cb3dSCy Schubert check_gen_fifo_consistency(void *fifo)
3102b15cb3dSCy Schubert {
3112b15cb3dSCy Schubert 	gen_fifo *pf;
3122b15cb3dSCy Schubert 	gen_node *pthis;
3132b15cb3dSCy Schubert 	gen_node **pptail;
3142b15cb3dSCy Schubert 
3152b15cb3dSCy Schubert 	pf = fifo;
3162b15cb3dSCy Schubert 	REQUIRE((NULL == pf->phead && NULL == pf->pptail) ||
3172b15cb3dSCy Schubert 		(NULL != pf->phead && NULL != pf->pptail));
3182b15cb3dSCy Schubert 
3192b15cb3dSCy Schubert 	pptail = &pf->phead;
3202b15cb3dSCy Schubert 	for (pthis = pf->phead;
3212b15cb3dSCy Schubert 	     pthis != NULL;
3222b15cb3dSCy Schubert 	     pthis = pthis->link)
3232b15cb3dSCy Schubert 		if (NULL != pthis->link)
3242b15cb3dSCy Schubert 			pptail = &pthis->link;
3252b15cb3dSCy Schubert 
3262b15cb3dSCy Schubert 	REQUIRE(NULL == pf->pptail || pptail == pf->pptail);
3272b15cb3dSCy Schubert }
3282b15cb3dSCy Schubert #endif	/* NTP_DEBUG_LISTS_H */
329