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