Coverage Report

Created: 2023-05-19 06:16

/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 */