/src/ntp-dev/libntp/recvbuff.c
Line | Count | Source (jump to first uncovered line) |
1 | | #ifdef HAVE_CONFIG_H |
2 | | # include <config.h> |
3 | | #endif |
4 | | |
5 | | #include <stdio.h> |
6 | | |
7 | | #include "ntp_assert.h" |
8 | | #include "ntp_syslog.h" |
9 | | #include "ntp_stdlib.h" |
10 | | #include "ntp_lists.h" |
11 | | #include "recvbuff.h" |
12 | | #include "iosignal.h" |
13 | | |
14 | | |
15 | | /* |
16 | | * Memory allocation |
17 | | */ |
18 | | static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ |
19 | | static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */ |
20 | | static u_long volatile total_recvbufs; /* total recvbufs currently in use */ |
21 | | static u_long volatile lowater_adds; /* number of times we have added memory */ |
22 | | static u_long volatile buffer_shortfall;/* number of missed free receive buffers |
23 | | between replenishments */ |
24 | | |
25 | | static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; |
26 | | static recvbuf_t * free_recv_list; |
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 | | */ |
35 | | static CRITICAL_SECTION RecvLock; |
36 | | # define LOCK() EnterCriticalSection(&RecvLock) |
37 | | # define UNLOCK() LeaveCriticalSection(&RecvLock) |
38 | | #else |
39 | 0 | # define LOCK() do {} while (FALSE) |
40 | 0 | # define UNLOCK() do {} while (FALSE) |
41 | | #endif |
42 | | |
43 | | #ifdef DEBUG |
44 | | static void uninit_recvbuff(void); |
45 | | #endif |
46 | | |
47 | | |
48 | | u_long |
49 | | free_recvbuffs (void) |
50 | 0 | { |
51 | 0 | return free_recvbufs; |
52 | 0 | } |
53 | | |
54 | | u_long |
55 | | full_recvbuffs (void) |
56 | 0 | { |
57 | 0 | return full_recvbufs; |
58 | 0 | } |
59 | | |
60 | | u_long |
61 | | total_recvbuffs (void) |
62 | 0 | { |
63 | 0 | return total_recvbufs; |
64 | 0 | } |
65 | | |
66 | | u_long |
67 | | lowater_additions(void) |
68 | 0 | { |
69 | 0 | return lowater_adds; |
70 | 0 | } |
71 | | |
72 | | static inline void |
73 | | initialise_buffer(recvbuf_t *buff) |
74 | 0 | { |
75 | 0 | ZERO(*buff); |
76 | 0 | } |
77 | | |
78 | | static void |
79 | | create_buffers(int nbufs) |
80 | 1 | { |
81 | 1 | register recvbuf_t *bufp; |
82 | 1 | int i, abuf; |
83 | | |
84 | 1 | abuf = nbufs + buffer_shortfall; |
85 | 1 | buffer_shortfall = 0; |
86 | | |
87 | | #ifndef DEBUG |
88 | | bufp = eallocarray(abuf, sizeof(*bufp)); |
89 | | #endif |
90 | | |
91 | 11 | for (i = 0; i < abuf; i++) { |
92 | 10 | #ifdef DEBUG |
93 | | /* |
94 | | * Allocate each buffer individually so they can be |
95 | | * free()d during ntpd shutdown on DEBUG builds to |
96 | | * keep them out of heap leak reports. |
97 | | */ |
98 | 10 | bufp = emalloc_zero(sizeof(*bufp)); |
99 | 10 | #endif |
100 | 10 | LINK_SLIST(free_recv_list, bufp, link); |
101 | 10 | bufp++; |
102 | 10 | free_recvbufs++; |
103 | 10 | total_recvbufs++; |
104 | 10 | } |
105 | 1 | lowater_adds++; |
106 | 1 | } |
107 | | |
108 | | void |
109 | | init_recvbuff(int nbufs) |
110 | 1 | { |
111 | | |
112 | | /* |
113 | | * Init buffer free list and stat counters |
114 | | */ |
115 | 1 | free_recvbufs = total_recvbufs = 0; |
116 | 1 | full_recvbufs = lowater_adds = 0; |
117 | | |
118 | 1 | create_buffers(nbufs); |
119 | | |
120 | | #if defined(SYS_WINNT) |
121 | | InitializeCriticalSection(&RecvLock); |
122 | | #endif |
123 | | |
124 | 1 | #ifdef DEBUG |
125 | 1 | atexit(&uninit_recvbuff); |
126 | 1 | #endif |
127 | 1 | } |
128 | | |
129 | | |
130 | | #ifdef DEBUG |
131 | | static void |
132 | | uninit_recvbuff(void) |
133 | 1 | { |
134 | 1 | recvbuf_t *rbunlinked; |
135 | | |
136 | 1 | for (;;) { |
137 | 1 | UNLINK_FIFO(rbunlinked, full_recv_fifo, link); |
138 | 1 | if (rbunlinked == NULL) |
139 | 1 | break; |
140 | 0 | free(rbunlinked); |
141 | 0 | } |
142 | | |
143 | 11 | for (;;) { |
144 | 11 | UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); |
145 | 11 | if (rbunlinked == NULL) |
146 | 1 | break; |
147 | 10 | free(rbunlinked); |
148 | 10 | } |
149 | 1 | } |
150 | | #endif /* DEBUG */ |
151 | | |
152 | | |
153 | | /* |
154 | | * freerecvbuf - make a single recvbuf available for reuse |
155 | | */ |
156 | | void |
157 | | freerecvbuf(recvbuf_t *rb) |
158 | 0 | { |
159 | 0 | if (rb) { |
160 | 0 | LOCK(); |
161 | 0 | rb->used--; |
162 | 0 | if (rb->used != 0) |
163 | 0 | msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); |
164 | 0 | LINK_SLIST(free_recv_list, rb, link); |
165 | 0 | free_recvbufs++; |
166 | 0 | UNLOCK(); |
167 | 0 | } |
168 | 0 | } |
169 | | |
170 | | |
171 | | void |
172 | | add_full_recv_buffer(recvbuf_t *rb) |
173 | 0 | { |
174 | 0 | if (rb == NULL) { |
175 | 0 | msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); |
176 | 0 | return; |
177 | 0 | } |
178 | 0 | LOCK(); |
179 | 0 | LINK_FIFO(full_recv_fifo, rb, link); |
180 | 0 | full_recvbufs++; |
181 | 0 | UNLOCK(); |
182 | 0 | } |
183 | | |
184 | | |
185 | | recvbuf_t * |
186 | | get_free_recv_buffer(void) |
187 | 0 | { |
188 | 0 | recvbuf_t *buffer; |
189 | |
|
190 | 0 | LOCK(); |
191 | 0 | UNLINK_HEAD_SLIST(buffer, free_recv_list, link); |
192 | 0 | if (buffer != NULL) { |
193 | 0 | free_recvbufs--; |
194 | 0 | initialise_buffer(buffer); |
195 | 0 | buffer->used++; |
196 | 0 | } else { |
197 | 0 | buffer_shortfall++; |
198 | 0 | } |
199 | 0 | UNLOCK(); |
200 | |
|
201 | 0 | return buffer; |
202 | 0 | } |
203 | | |
204 | | |
205 | | #ifdef HAVE_IO_COMPLETION_PORT |
206 | | recvbuf_t * |
207 | | get_free_recv_buffer_alloc(void) |
208 | | { |
209 | | recvbuf_t *buffer; |
210 | | |
211 | | buffer = get_free_recv_buffer(); |
212 | | if (NULL == buffer) { |
213 | | create_buffers(RECV_INC); |
214 | | buffer = get_free_recv_buffer(); |
215 | | } |
216 | | ENSURE(buffer != NULL); |
217 | | return (buffer); |
218 | | } |
219 | | #endif |
220 | | |
221 | | |
222 | | recvbuf_t * |
223 | | get_full_recv_buffer(void) |
224 | 0 | { |
225 | 0 | recvbuf_t * rbuf; |
226 | |
|
227 | 0 | LOCK(); |
228 | | |
229 | | #ifdef HAVE_SIGNALED_IO |
230 | | /* |
231 | | * make sure there are free buffers when we |
232 | | * wander off to do lengthy packet processing with |
233 | | * any buffer we grab from the full list. |
234 | | * |
235 | | * fixes malloc() interrupted by SIGIO risk |
236 | | * (Bug 889) |
237 | | */ |
238 | | if (NULL == free_recv_list || buffer_shortfall > 0) { |
239 | | /* |
240 | | * try to get us some more buffers |
241 | | */ |
242 | | create_buffers(RECV_INC); |
243 | | } |
244 | | #endif |
245 | | |
246 | | /* |
247 | | * try to grab a full buffer |
248 | | */ |
249 | 0 | UNLINK_FIFO(rbuf, full_recv_fifo, link); |
250 | 0 | if (rbuf != NULL) |
251 | 0 | full_recvbufs--; |
252 | 0 | UNLOCK(); |
253 | |
|
254 | 0 | return rbuf; |
255 | 0 | } |
256 | | |
257 | | |
258 | | /* |
259 | | * purge_recv_buffers_for_fd() - purges any previously-received input |
260 | | * from a given file descriptor. |
261 | | */ |
262 | | void |
263 | | purge_recv_buffers_for_fd( |
264 | | int fd |
265 | | ) |
266 | 0 | { |
267 | 0 | recvbuf_t *rbufp; |
268 | 0 | recvbuf_t *next; |
269 | 0 | recvbuf_t *punlinked; |
270 | |
|
271 | 0 | LOCK(); |
272 | |
|
273 | 0 | for (rbufp = HEAD_FIFO(full_recv_fifo); |
274 | 0 | rbufp != NULL; |
275 | 0 | rbufp = next) { |
276 | 0 | next = rbufp->link; |
277 | | # ifdef HAVE_IO_COMPLETION_PORT |
278 | | if (rbufp->dstadr == NULL && rbufp->fd == fd) |
279 | | # else |
280 | 0 | if (rbufp->fd == fd) |
281 | 0 | # endif |
282 | 0 | { |
283 | 0 | UNLINK_MID_FIFO(punlinked, full_recv_fifo, |
284 | 0 | rbufp, link, recvbuf_t); |
285 | 0 | INSIST(punlinked == rbufp); |
286 | 0 | full_recvbufs--; |
287 | 0 | freerecvbuf(rbufp); |
288 | 0 | } |
289 | 0 | } |
290 | |
|
291 | 0 | UNLOCK(); |
292 | 0 | } |
293 | | |
294 | | |
295 | | /* |
296 | | * Checks to see if there are buffers to process |
297 | | */ |
298 | | isc_boolean_t has_full_recv_buffer(void) |
299 | 0 | { |
300 | 0 | if (HEAD_FIFO(full_recv_fifo) != NULL) |
301 | 0 | return (ISC_TRUE); |
302 | 0 | else |
303 | 0 | return (ISC_FALSE); |
304 | 0 | } |
305 | | |
306 | | |
307 | | #ifdef NTP_DEBUG_LISTS_H |
308 | | void |
309 | | check_gen_fifo_consistency(void *fifo) |
310 | 1 | { |
311 | 1 | gen_fifo *pf; |
312 | 1 | gen_node *pthis; |
313 | 1 | gen_node **pptail; |
314 | | |
315 | 1 | pf = fifo; |
316 | 1 | REQUIRE((NULL == pf->phead && NULL == pf->pptail) || |
317 | 0 | (NULL != pf->phead && NULL != pf->pptail)); |
318 | | |
319 | 0 | pptail = &pf->phead; |
320 | 1 | for (pthis = pf->phead; |
321 | 1 | pthis != NULL; |
322 | 1 | pthis = pthis->link) |
323 | 0 | if (NULL != pthis->link) |
324 | 0 | pptail = &pthis->link; |
325 | | |
326 | 1 | REQUIRE(NULL == pf->pptail || pptail == pf->pptail); |
327 | 1 | } |
328 | | #endif /* NTP_DEBUG_LISTS_H */ |