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