recvbuff.c revision 54359
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_stdlib.h"
9#include "ntp_syslog.h"
10#include "ntp_io.h"
11#include "recvbuff.h"
12#include "iosignal.h"
13
14/*
15 * Memory allocation
16 */
17static u_long volatile full_recvbufs;		/* number of recvbufs on fulllist */
18static u_long volatile free_recvbufs;		/* number of recvbufs on freelist */
19static u_long volatile total_recvbufs;		/* total recvbufs currently in use */
20static u_long volatile lowater_adds;	/* number of times we have added memory */
21
22static	struct recvbuf *volatile freelist;  /* free buffers */
23static	struct recvbuf *volatile fulllist;  /* lifo buffers with data */
24static	struct recvbuf *volatile beginlist; /* fifo buffers with data */
25
26#if defined(HAVE_IO_COMPLETION_PORT)
27static HANDLE fulldatabufferevent;
28static CRITICAL_SECTION RecvCritSection;
29# define RECV_BLOCK_IO()	EnterCriticalSection(&RecvCritSection)
30# define RECV_UNBLOCK_IO()	LeaveCriticalSection(&RecvCritSection)
31#else
32# define RECV_BLOCK_IO()
33# define RECV_UNBLOCK_IO()
34#endif
35
36u_long
37free_recvbuffs (void)
38{
39	return free_recvbufs;
40}
41
42u_long
43full_recvbuffs (void)
44{
45	return free_recvbufs;
46}
47
48u_long
49total_recvbuffs (void)
50{
51	return free_recvbufs;
52}
53
54u_long
55lowater_additions(void)
56{
57	return lowater_adds;
58}
59
60static void
61initialise_buffer(struct recvbuf *buff)
62{
63	memset((char *) buff, 0, sizeof(struct recvbuf));
64
65#if defined HAVE_IO_COMPLETION_PORT
66	buff->iocompletioninfo.overlapped.hEvent = CreateEvent(NULL, FALSE,FALSE, NULL);
67	buff->wsabuff.len = RX_BUFF_SIZE;
68	buff->wsabuff.buf = (char *) buff->recv_buffer;
69#endif
70}
71
72static void
73create_buffers(void)
74{
75	register struct recvbuf *buf;
76	int i;
77	buf = (struct recvbuf *)
78	    emalloc(RECV_INC*sizeof(struct recvbuf));
79	for (i = 0; i < RECV_INC; i++)
80	{
81		initialise_buffer(buf);
82		buf->next = (struct recvbuf *) freelist;
83		freelist = buf;
84		buf++;
85	}
86
87	free_recvbufs += RECV_INC;
88	total_recvbufs += RECV_INC;
89	lowater_adds++;
90}
91
92void
93init_recvbuff(int nbufs)
94{
95	register struct recvbuf *buf;
96	int i;
97
98	/*
99	 * Init buffer free list and stat counters
100	 */
101	freelist = 0;
102
103	buf = (struct recvbuf *)
104	    emalloc(nbufs*sizeof(struct recvbuf));
105	for (i = 0; i < nbufs; i++)
106	{
107		initialise_buffer(buf);
108		buf->next = (struct recvbuf *) freelist;
109		freelist = buf;
110		buf++;
111	}
112
113	fulllist = 0;
114	free_recvbufs = total_recvbufs = nbufs;
115	full_recvbufs = lowater_adds = 0;
116
117#if defined(HAVE_IO_COMPLETION_PORT)
118	InitializeCriticalSection(&RecvCritSection);
119	fulldatabufferevent = CreateEvent(NULL, FALSE,FALSE, NULL);
120#endif
121
122}
123
124#if defined(HAVE_IO_COMPLETION_PORT)
125
126/*  Return the new full buffer event handle . This handle is
127 *  signalled when a recv buffer is placed in the full list.
128 */
129HANDLE
130get_recv_buff_event()
131{
132	return fulldatabufferevent;
133}
134#endif
135
136/*
137 * getrecvbufs - get receive buffers which have data in them
138 *
139 *
140 */
141
142struct recvbuf *
143getrecvbufs(void)
144{
145	struct recvbuf *rb = NULL; /* nothing has arrived */;
146
147	RECV_BLOCK_IO();
148	if (full_recvbufs == 0)
149	{
150#ifdef DEBUG
151		if (debug > 4)
152		    printf("getrecvbufs called, no action here\n");
153#endif
154	}
155	else {
156
157		/*
158		 * Get the fulllist chain and mark it empty
159		 */
160#ifdef DEBUG
161		if (debug > 4)
162		    printf("getrecvbufs returning %ld buffers\n", full_recvbufs);
163#endif
164		rb = beginlist;
165		fulllist = 0;
166		full_recvbufs = 0;
167
168		/*
169		 * Check to see if we're below the low water mark.
170		 */
171		if (free_recvbufs <= RECV_LOWAT)
172		{
173			if (total_recvbufs >= RECV_TOOMANY)
174			    msyslog(LOG_ERR, "too many recvbufs allocated (%ld)",
175				    total_recvbufs);
176			else
177			{
178				create_buffers();
179			}
180		}
181	}
182	RECV_UNBLOCK_IO();
183
184	/*
185	 * Return the chain
186	 */
187	return rb;
188}
189
190/*
191 * freerecvbuf - make a single recvbuf available for reuse
192 */
193void
194freerecvbuf(
195	struct recvbuf *rb
196	)
197{
198	RECV_BLOCK_IO();
199	BLOCKIO();
200	rb->next = (struct recvbuf *) freelist;
201	freelist = rb;
202	free_recvbufs++;
203	UNBLOCKIO();
204	RECV_UNBLOCK_IO();
205}
206
207
208void
209add_full_recv_buffer(
210	struct recvbuf *rb
211	)
212{
213	RECV_BLOCK_IO();
214	if (full_recvbufs == 0)
215	{
216		beginlist = rb;
217		rb->next = 0;
218	}
219	else
220	{
221		rb->next = fulllist->next;
222		fulllist->next = rb;
223	}
224	fulllist = rb;
225	full_recvbufs++;
226
227#if defined(HAVE_IO_COMPLETION_PORT)
228	if (!SetEvent(fulldatabufferevent)) {
229		msyslog(LOG_ERR, "Can't set receive buffer event");
230	}
231#endif
232	RECV_UNBLOCK_IO();
233}
234
235struct recvbuf *
236get_free_recv_buffer(void)
237{
238	struct recvbuf * buffer = NULL;
239	RECV_BLOCK_IO();
240	if (free_recvbufs <= RECV_LOWAT)
241		{
242			if (total_recvbufs >= RECV_TOOMANY) {
243			    msyslog(LOG_ERR, "too many recvbufs allocated (%ld)",
244				    total_recvbufs);
245			}
246			else
247			{
248				create_buffers();
249			}
250		}
251
252	if (free_recvbufs > 0)
253	{
254		buffer = freelist;
255		freelist = buffer->next;
256		buffer->next = NULL;
257		--free_recvbufs;
258	}
259
260	RECV_UNBLOCK_IO();
261	return buffer;
262}
263
264struct recvbuf *
265get_full_recv_buffer(void)
266{
267	struct recvbuf * buffer = NULL;
268	RECV_BLOCK_IO();
269	if (full_recvbufs > 0) {
270		--full_recvbufs;
271		buffer = beginlist;
272		beginlist = buffer->next;
273		buffer->next = NULL;
274	}
275	RECV_UNBLOCK_IO();
276	return buffer;
277}
278