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 # define LOCK() do {} while (FALSE) 40 # 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 { 51 return free_recvbufs; 52 } 53 54 u_long 55 full_recvbuffs (void) 56 { 57 return full_recvbufs; 58 } 59 60 u_long 61 total_recvbuffs (void) 62 { 63 return total_recvbufs; 64 } 65 66 u_long 67 lowater_additions(void) 68 { 69 return lowater_adds; 70 } 71 72 static inline void 73 initialise_buffer(recvbuf_t *buff) 74 { 75 ZERO(*buff); 76 } 77 78 static void 79 create_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 #ifndef DEBUG 88 bufp = eallocarray(abuf, sizeof(*bufp)); 89 #endif 90 91 for (i = 0; i < abuf; i++) { 92 #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 bufp = emalloc_zero(sizeof(*bufp)); 99 #endif 100 LINK_SLIST(free_recv_list, bufp, link); 101 bufp++; 102 free_recvbufs++; 103 total_recvbufs++; 104 } 105 lowater_adds++; 106 } 107 108 void 109 init_recvbuff(int nbufs) 110 { 111 112 /* 113 * Init buffer free list and stat counters 114 */ 115 free_recvbufs = total_recvbufs = 0; 116 full_recvbufs = lowater_adds = 0; 117 118 create_buffers(nbufs); 119 120 #if defined(SYS_WINNT) 121 InitializeCriticalSection(&RecvLock); 122 #endif 123 124 #ifdef DEBUG 125 atexit(&uninit_recvbuff); 126 #endif 127 } 128 129 130 #ifdef DEBUG 131 static void 132 uninit_recvbuff(void) 133 { 134 recvbuf_t *rbunlinked; 135 136 for (;;) { 137 UNLINK_FIFO(rbunlinked, full_recv_fifo, link); 138 if (rbunlinked == NULL) 139 break; 140 free(rbunlinked); 141 } 142 143 for (;;) { 144 UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); 145 if (rbunlinked == NULL) 146 break; 147 free(rbunlinked); 148 } 149 } 150 #endif /* DEBUG */ 151 152 153 /* 154 * freerecvbuf - make a single recvbuf available for reuse 155 */ 156 void 157 freerecvbuf(recvbuf_t *rb) 158 { 159 if (rb) { 160 LOCK(); 161 rb->used--; 162 if (rb->used != 0) 163 msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 164 LINK_SLIST(free_recv_list, rb, link); 165 free_recvbufs++; 166 UNLOCK(); 167 } 168 } 169 170 171 void 172 add_full_recv_buffer(recvbuf_t *rb) 173 { 174 if (rb == NULL) { 175 msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); 176 return; 177 } 178 LOCK(); 179 LINK_FIFO(full_recv_fifo, rb, link); 180 full_recvbufs++; 181 UNLOCK(); 182 } 183 184 185 recvbuf_t * 186 get_free_recv_buffer(void) 187 { 188 recvbuf_t *buffer; 189 190 LOCK(); 191 UNLINK_HEAD_SLIST(buffer, free_recv_list, link); 192 if (buffer != NULL) { 193 free_recvbufs--; 194 initialise_buffer(buffer); 195 buffer->used++; 196 } else { 197 buffer_shortfall++; 198 } 199 UNLOCK(); 200 201 return buffer; 202 } 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 { 225 recvbuf_t * rbuf; 226 227 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 UNLINK_FIFO(rbuf, full_recv_fifo, link); 250 if (rbuf != NULL) 251 full_recvbufs--; 252 UNLOCK(); 253 254 return rbuf; 255 } 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 { 267 recvbuf_t *rbufp; 268 recvbuf_t *next; 269 recvbuf_t *punlinked; 270 271 LOCK(); 272 273 for (rbufp = HEAD_FIFO(full_recv_fifo); 274 rbufp != NULL; 275 rbufp = next) { 276 next = rbufp->link; 277 # ifdef HAVE_IO_COMPLETION_PORT 278 if (rbufp->dstadr == NULL && rbufp->fd == fd) 279 # else 280 if (rbufp->fd == fd) 281 # endif 282 { 283 UNLINK_MID_FIFO(punlinked, full_recv_fifo, 284 rbufp, link, recvbuf_t); 285 INSIST(punlinked == rbufp); 286 full_recvbufs--; 287 freerecvbuf(rbufp); 288 } 289 } 290 291 UNLOCK(); 292 } 293 294 295 /* 296 * Checks to see if there are buffers to process 297 */ 298 isc_boolean_t has_full_recv_buffer(void) 299 { 300 if (HEAD_FIFO(full_recv_fifo) != NULL) 301 return (ISC_TRUE); 302 else 303 return (ISC_FALSE); 304 } 305 306 307 #ifdef NTP_DEBUG_LISTS_H 308 void 309 check_gen_fifo_consistency(void *fifo) 310 { 311 gen_fifo *pf; 312 gen_node *pthis; 313 gen_node **pptail; 314 315 pf = fifo; 316 REQUIRE((NULL == pf->phead && NULL == pf->pptail) || 317 (NULL != pf->phead && NULL != pf->pptail)); 318 319 pptail = &pf->phead; 320 for (pthis = pf->phead; 321 pthis != NULL; 322 pthis = pthis->link) 323 if (NULL != pthis->link) 324 pptail = &pthis->link; 325 326 REQUIRE(NULL == pf->pptail || pptail == pf->pptail); 327 } 328 #endif /* NTP_DEBUG_LISTS_H */ 329