xref: /freebsd/contrib/ntp/libntp/recvbuff.c (revision ea906c4152774dff300bb26fbfc1e4188351c89a)
1c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H
2c0b746e5SOllivier Robert # include <config.h>
3c0b746e5SOllivier Robert #endif
4c0b746e5SOllivier Robert 
5c0b746e5SOllivier Robert #include <stdio.h>
6c0b746e5SOllivier Robert #include "ntp_machine.h"
7c0b746e5SOllivier Robert #include "ntp_fp.h"
8c0b746e5SOllivier Robert #include "ntp_syslog.h"
9224ba2bdSOllivier Robert #include "ntp_stdlib.h"
10c0b746e5SOllivier Robert #include "ntp_io.h"
11c0b746e5SOllivier Robert #include "recvbuff.h"
12c0b746e5SOllivier Robert #include "iosignal.h"
13c0b746e5SOllivier Robert 
14ea906c41SOllivier Robert #include <isc/list.h>
15c0b746e5SOllivier Robert /*
16c0b746e5SOllivier Robert  * Memory allocation
17c0b746e5SOllivier Robert  */
18c0b746e5SOllivier Robert static u_long volatile full_recvbufs;	/* number of recvbufs on fulllist */
19c0b746e5SOllivier Robert static u_long volatile free_recvbufs;	/* number of recvbufs on freelist */
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 
25ea906c41SOllivier Robert static ISC_LIST(recvbuf_t)	full_recv_list;	/* Currently used recv buffers */
26ea906c41SOllivier Robert static ISC_LIST(recvbuf_t)	free_recv_list;	/* Currently unused buffers */
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
39ea906c41SOllivier Robert # define LOCK()
40ea906c41SOllivier Robert # define UNLOCK()
41c0b746e5SOllivier Robert #endif
42c0b746e5SOllivier Robert 
43c0b746e5SOllivier Robert u_long
44c0b746e5SOllivier Robert free_recvbuffs (void)
45c0b746e5SOllivier Robert {
46c0b746e5SOllivier Robert 	return free_recvbufs;
47c0b746e5SOllivier Robert }
48c0b746e5SOllivier Robert 
49c0b746e5SOllivier Robert u_long
50c0b746e5SOllivier Robert full_recvbuffs (void)
51c0b746e5SOllivier Robert {
52ea906c41SOllivier Robert 	return full_recvbufs;
53c0b746e5SOllivier Robert }
54c0b746e5SOllivier Robert 
55c0b746e5SOllivier Robert u_long
56c0b746e5SOllivier Robert total_recvbuffs (void)
57c0b746e5SOllivier Robert {
58ea906c41SOllivier Robert 	return total_recvbufs;
59c0b746e5SOllivier Robert }
60c0b746e5SOllivier Robert 
61c0b746e5SOllivier Robert u_long
62c0b746e5SOllivier Robert lowater_additions(void)
63c0b746e5SOllivier Robert {
64c0b746e5SOllivier Robert 	return lowater_adds;
65c0b746e5SOllivier Robert }
66c0b746e5SOllivier Robert 
67c0b746e5SOllivier Robert static void
68ea906c41SOllivier Robert initialise_buffer(recvbuf_t *buff)
69c0b746e5SOllivier Robert {
70ea906c41SOllivier Robert 	memset((char *) buff, 0, sizeof(recvbuf_t));
71c0b746e5SOllivier Robert 
72ea906c41SOllivier Robert #if defined SYS_WINNT
73c0b746e5SOllivier Robert 	buff->wsabuff.len = RX_BUFF_SIZE;
74c0b746e5SOllivier Robert 	buff->wsabuff.buf = (char *) buff->recv_buffer;
75c0b746e5SOllivier Robert #endif
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 
87ea906c41SOllivier Robert 	bufp = (recvbuf_t *) emalloc(abuf*sizeof(recvbuf_t));
88ea906c41SOllivier Robert 
89ea906c41SOllivier Robert 	for (i = 0; i < abuf; i++)
90ea906c41SOllivier Robert 	{
91ea906c41SOllivier Robert 		memset((char *) bufp, 0, sizeof(recvbuf_t));
92ea906c41SOllivier Robert 		ISC_LIST_APPEND(free_recv_list, bufp, link);
93ea906c41SOllivier Robert 		bufp++;
94ea906c41SOllivier Robert 		free_recvbufs++;
95ea906c41SOllivier Robert 		total_recvbufs++;
96ea906c41SOllivier Robert 	}
97c0b746e5SOllivier Robert 	lowater_adds++;
98c0b746e5SOllivier Robert }
99c0b746e5SOllivier Robert 
100c0b746e5SOllivier Robert void
101c0b746e5SOllivier Robert init_recvbuff(int nbufs)
102c0b746e5SOllivier Robert {
103c0b746e5SOllivier Robert 
104c0b746e5SOllivier Robert 	/*
105c0b746e5SOllivier Robert 	 * Init buffer free list and stat counters
106c0b746e5SOllivier Robert 	 */
107ea906c41SOllivier Robert 	ISC_LIST_INIT(full_recv_list);
108ea906c41SOllivier Robert 	ISC_LIST_INIT(free_recv_list);
109ea906c41SOllivier Robert 	free_recvbufs = total_recvbufs = 0;
110c0b746e5SOllivier Robert 	full_recvbufs = lowater_adds = 0;
111c0b746e5SOllivier Robert 
112ea906c41SOllivier Robert 	create_buffers(nbufs);
113ea906c41SOllivier Robert 
114ea906c41SOllivier Robert #if defined(SYS_WINNT)
115ea906c41SOllivier Robert 	InitializeCriticalSection(&RecvLock);
116c0b746e5SOllivier Robert #endif
117c0b746e5SOllivier Robert 
118c0b746e5SOllivier Robert }
119c0b746e5SOllivier Robert 
120c0b746e5SOllivier Robert /*
121c0b746e5SOllivier Robert  * freerecvbuf - make a single recvbuf available for reuse
122c0b746e5SOllivier Robert  */
123c0b746e5SOllivier Robert void
124ea906c41SOllivier Robert freerecvbuf(recvbuf_t *rb)
125c0b746e5SOllivier Robert {
126ea906c41SOllivier Robert 	if (rb == NULL) {
127ea906c41SOllivier Robert 		msyslog(LOG_ERR, "freerecvbuff received NULL buffer");
128ea906c41SOllivier Robert 		return;
129ea906c41SOllivier Robert 	}
130ea906c41SOllivier Robert 
131ea906c41SOllivier Robert 	LOCK();
132ea906c41SOllivier Robert 	(rb->used)--;
133ea906c41SOllivier Robert 	if (rb->used != 0)
134ea906c41SOllivier Robert 		msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used);
135ea906c41SOllivier Robert 	ISC_LIST_APPEND(free_recv_list, rb, link);
136ea906c41SOllivier Robert #if defined SYS_WINNT
137ea906c41SOllivier Robert 	rb->wsabuff.len = RX_BUFF_SIZE;
138ea906c41SOllivier Robert 	rb->wsabuff.buf = (char *) rb->recv_buffer;
139ea906c41SOllivier Robert #endif
140c0b746e5SOllivier Robert 	free_recvbufs++;
141ea906c41SOllivier Robert 	UNLOCK();
142c0b746e5SOllivier Robert }
143c0b746e5SOllivier Robert 
144c0b746e5SOllivier Robert 
145c0b746e5SOllivier Robert void
146ea906c41SOllivier Robert add_full_recv_buffer(recvbuf_t *rb)
147c0b746e5SOllivier Robert {
148ea906c41SOllivier Robert 	if (rb == NULL) {
149ea906c41SOllivier Robert 		msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer");
150ea906c41SOllivier Robert 		return;
151c0b746e5SOllivier Robert 	}
152ea906c41SOllivier Robert 	LOCK();
153ea906c41SOllivier Robert 	ISC_LIST_APPEND(full_recv_list, rb, link);
154c0b746e5SOllivier Robert 	full_recvbufs++;
155ea906c41SOllivier Robert 	UNLOCK();
156c0b746e5SOllivier Robert }
157c0b746e5SOllivier Robert 
158ea906c41SOllivier Robert recvbuf_t *
159c0b746e5SOllivier Robert get_free_recv_buffer(void)
160c0b746e5SOllivier Robert {
161ea906c41SOllivier Robert 	recvbuf_t * buffer = NULL;
162ea906c41SOllivier Robert 	LOCK();
163ea906c41SOllivier Robert 	buffer = ISC_LIST_HEAD(free_recv_list);
164ea906c41SOllivier Robert 	if (buffer != NULL)
165c0b746e5SOllivier Robert 	{
166ea906c41SOllivier Robert 		ISC_LIST_DEQUEUE(free_recv_list, buffer, link);
167ea906c41SOllivier Robert 		free_recvbufs--;
168ea906c41SOllivier Robert 		initialise_buffer(buffer);
169ea906c41SOllivier Robert 		(buffer->used)++;
170c0b746e5SOllivier Robert 	}
171c0b746e5SOllivier Robert 	else
172c0b746e5SOllivier Robert 	{
173ea906c41SOllivier Robert 		buffer_shortfall++;
174c0b746e5SOllivier Robert 	}
175ea906c41SOllivier Robert 	UNLOCK();
176ea906c41SOllivier Robert 	return (buffer);
177c0b746e5SOllivier Robert }
178c0b746e5SOllivier Robert 
179ea906c41SOllivier Robert #ifdef HAVE_IO_COMPLETION_PORT
180ea906c41SOllivier Robert recvbuf_t *
181ea906c41SOllivier Robert get_free_recv_buffer_alloc(void)
182c0b746e5SOllivier Robert {
183ea906c41SOllivier Robert 	recvbuf_t * buffer = get_free_recv_buffer();
184ea906c41SOllivier Robert 	if (buffer == NULL)
185ea906c41SOllivier Robert 	{
186ea906c41SOllivier Robert 		create_buffers(RECV_INC);
187ea906c41SOllivier Robert 		buffer = get_free_recv_buffer();
188c0b746e5SOllivier Robert 	}
189ea906c41SOllivier Robert 	return (buffer);
190c0b746e5SOllivier Robert }
191ea906c41SOllivier Robert #endif
192c0b746e5SOllivier Robert 
193ea906c41SOllivier Robert recvbuf_t *
194c0b746e5SOllivier Robert get_full_recv_buffer(void)
195c0b746e5SOllivier Robert {
196ea906c41SOllivier Robert 	recvbuf_t *rbuf;
197ea906c41SOllivier Robert 	LOCK();
198ea906c41SOllivier Robert 
199ea906c41SOllivier Robert #ifdef HAVE_SIGNALED_IO
200ea906c41SOllivier Robert 	/*
201ea906c41SOllivier Robert 	 * make sure there are free buffers when we
202ea906c41SOllivier Robert 	 * wander off to do lengthy paket processing with
203ea906c41SOllivier Robert 	 * any buffer we grab from the full list.
204ea906c41SOllivier Robert 	 *
205ea906c41SOllivier Robert 	 * fixes malloc() interrupted by SIGIO risk
206ea906c41SOllivier Robert 	 * (Bug 889)
207ea906c41SOllivier Robert 	 */
208ea906c41SOllivier Robert 	rbuf = ISC_LIST_HEAD(free_recv_list);
209ea906c41SOllivier Robert 	if (rbuf == NULL || buffer_shortfall > 0) {
210ea906c41SOllivier Robert 		/*
211ea906c41SOllivier Robert 		 * try to get us some more buffers
212ea906c41SOllivier Robert 		 */
213ea906c41SOllivier Robert 		create_buffers(RECV_INC);
214c0b746e5SOllivier Robert 	}
215ea906c41SOllivier Robert #endif
216ea906c41SOllivier Robert 
217ea906c41SOllivier Robert 	/*
218ea906c41SOllivier Robert 	 * try to grab a full buffer
219ea906c41SOllivier Robert 	 */
220ea906c41SOllivier Robert 	rbuf = ISC_LIST_HEAD(full_recv_list);
221ea906c41SOllivier Robert 	if (rbuf != NULL)
222ea906c41SOllivier Robert 	{
223ea906c41SOllivier Robert 		ISC_LIST_DEQUEUE(full_recv_list, rbuf, link);
224ea906c41SOllivier Robert 		--full_recvbufs;
225ea906c41SOllivier Robert 	}
226ea906c41SOllivier Robert 	else
227ea906c41SOllivier Robert 	{
228ea906c41SOllivier Robert 		/*
229ea906c41SOllivier Robert 		 * Make sure we reset the full count to 0
230ea906c41SOllivier Robert 		 */
231ea906c41SOllivier Robert 		full_recvbufs = 0;
232ea906c41SOllivier Robert 	}
233ea906c41SOllivier Robert 	UNLOCK();
234ea906c41SOllivier Robert 	return (rbuf);
235ea906c41SOllivier Robert }
236ea906c41SOllivier Robert 
237ea906c41SOllivier Robert /*
238ea906c41SOllivier Robert  * Checks to see if there are buffers to process
239ea906c41SOllivier Robert  */
240ea906c41SOllivier Robert isc_boolean_t has_full_recv_buffer(void)
241ea906c41SOllivier Robert {
242ea906c41SOllivier Robert 	if (ISC_LIST_HEAD(full_recv_list) != NULL)
243ea906c41SOllivier Robert 		return (ISC_TRUE);
244ea906c41SOllivier Robert 	else
245ea906c41SOllivier Robert 		return (ISC_FALSE);
246c0b746e5SOllivier Robert }
247