154359Sroberto#ifdef HAVE_CONFIG_H 254359Sroberto# include <config.h> 354359Sroberto#endif 454359Sroberto 554359Sroberto#include <stdio.h> 6285612Sdelphij 7285612Sdelphij#include "ntp_assert.h" 882498Sroberto#include "ntp_syslog.h" 954359Sroberto#include "ntp_stdlib.h" 10285612Sdelphij#include "ntp_lists.h" 1154359Sroberto#include "recvbuff.h" 1254359Sroberto#include "iosignal.h" 1354359Sroberto 14285612Sdelphij 1554359Sroberto/* 1654359Sroberto * Memory allocation 1754359Sroberto */ 18285612Sdelphijstatic u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ 19285612Sdelphijstatic u_long volatile free_recvbufs; /* recvbufs on free_recv_list */ 20182007Srobertostatic u_long volatile total_recvbufs; /* total recvbufs currently in use */ 2154359Srobertostatic u_long volatile lowater_adds; /* number of times we have added memory */ 22182007Srobertostatic u_long volatile buffer_shortfall;/* number of missed free receive buffers 23285612Sdelphij between replenishments */ 2454359Sroberto 25285612Sdelphijstatic DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; 26285612Sdelphijstatic recvbuf_t * free_recv_list; 2754359Sroberto 28182007Sroberto#if defined(SYS_WINNT) 29182007Sroberto 30182007Sroberto/* 31182007Sroberto * For Windows we need to set up a lock to manipulate the 32182007Sroberto * recv buffers to prevent corruption. We keep it lock for as 33182007Sroberto * short a time as possible 34182007Sroberto */ 35182007Srobertostatic CRITICAL_SECTION RecvLock; 36182007Sroberto# define LOCK() EnterCriticalSection(&RecvLock) 37182007Sroberto# define UNLOCK() LeaveCriticalSection(&RecvLock) 3854359Sroberto#else 39285612Sdelphij# define LOCK() do {} while (FALSE) 40285612Sdelphij# define UNLOCK() do {} while (FALSE) 4154359Sroberto#endif 4254359Sroberto 43285612Sdelphij#ifdef DEBUG 44285612Sdelphijstatic void uninit_recvbuff(void); 45285612Sdelphij#endif 46285612Sdelphij 47285612Sdelphij 4854359Srobertou_long 4954359Srobertofree_recvbuffs (void) 5054359Sroberto{ 5154359Sroberto return free_recvbufs; 5254359Sroberto} 5354359Sroberto 5454359Srobertou_long 5554359Srobertofull_recvbuffs (void) 5654359Sroberto{ 57182007Sroberto return full_recvbufs; 5854359Sroberto} 5954359Sroberto 6054359Srobertou_long 6154359Srobertototal_recvbuffs (void) 6254359Sroberto{ 63182007Sroberto return total_recvbufs; 6454359Sroberto} 6554359Sroberto 6654359Srobertou_long 6754359Srobertolowater_additions(void) 6854359Sroberto{ 6954359Sroberto return lowater_adds; 7054359Sroberto} 7154359Sroberto 72285612Sdelphijstatic inline void 73182007Srobertoinitialise_buffer(recvbuf_t *buff) 7454359Sroberto{ 75285612Sdelphij ZERO(*buff); 7654359Sroberto} 7754359Sroberto 7854359Srobertostatic void 79182007Srobertocreate_buffers(int nbufs) 8054359Sroberto{ 81182007Sroberto register recvbuf_t *bufp; 82182007Sroberto int i, abuf; 83182007Sroberto 84182007Sroberto abuf = nbufs + buffer_shortfall; 85182007Sroberto buffer_shortfall = 0; 86182007Sroberto 87285612Sdelphij#ifndef DEBUG 88316069Sdelphij bufp = eallocarray(abuf, sizeof(*bufp)); 89285612Sdelphij#endif 90182007Sroberto 91285612Sdelphij for (i = 0; i < abuf; i++) { 92285612Sdelphij#ifdef DEBUG 93285612Sdelphij /* 94285612Sdelphij * Allocate each buffer individually so they can be 95285612Sdelphij * free()d during ntpd shutdown on DEBUG builds to 96285612Sdelphij * keep them out of heap leak reports. 97285612Sdelphij */ 98285612Sdelphij bufp = emalloc_zero(sizeof(*bufp)); 99285612Sdelphij#endif 100285612Sdelphij LINK_SLIST(free_recv_list, bufp, link); 101182007Sroberto bufp++; 102182007Sroberto free_recvbufs++; 103182007Sroberto total_recvbufs++; 10454359Sroberto } 10554359Sroberto lowater_adds++; 10654359Sroberto} 10754359Sroberto 10854359Srobertovoid 10954359Srobertoinit_recvbuff(int nbufs) 11054359Sroberto{ 11154359Sroberto 11254359Sroberto /* 11354359Sroberto * Init buffer free list and stat counters 11454359Sroberto */ 115182007Sroberto free_recvbufs = total_recvbufs = 0; 116182007Sroberto full_recvbufs = lowater_adds = 0; 11754359Sroberto 118182007Sroberto create_buffers(nbufs); 11954359Sroberto 120182007Sroberto#if defined(SYS_WINNT) 121182007Sroberto InitializeCriticalSection(&RecvLock); 12254359Sroberto#endif 12354359Sroberto 124285612Sdelphij#ifdef DEBUG 125285612Sdelphij atexit(&uninit_recvbuff); 126285612Sdelphij#endif 12754359Sroberto} 12854359Sroberto 129285612Sdelphij 130285612Sdelphij#ifdef DEBUG 131285612Sdelphijstatic void 132285612Sdelphijuninit_recvbuff(void) 133285612Sdelphij{ 134285612Sdelphij recvbuf_t *rbunlinked; 135285612Sdelphij 136285612Sdelphij for (;;) { 137285612Sdelphij UNLINK_FIFO(rbunlinked, full_recv_fifo, link); 138285612Sdelphij if (rbunlinked == NULL) 139285612Sdelphij break; 140285612Sdelphij free(rbunlinked); 141285612Sdelphij } 142285612Sdelphij 143285612Sdelphij for (;;) { 144285612Sdelphij UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); 145285612Sdelphij if (rbunlinked == NULL) 146285612Sdelphij break; 147285612Sdelphij free(rbunlinked); 148285612Sdelphij } 149285612Sdelphij} 150285612Sdelphij#endif /* DEBUG */ 151285612Sdelphij 152285612Sdelphij 15354359Sroberto/* 154182007Sroberto * freerecvbuf - make a single recvbuf available for reuse 15554359Sroberto */ 156182007Srobertovoid 157182007Srobertofreerecvbuf(recvbuf_t *rb) 15854359Sroberto{ 159298699Sdelphij if (rb) { 160298699Sdelphij LOCK(); 161298699Sdelphij rb->used--; 162298699Sdelphij if (rb->used != 0) 163298699Sdelphij msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 164298699Sdelphij LINK_SLIST(free_recv_list, rb, link); 165298699Sdelphij free_recvbufs++; 166298699Sdelphij UNLOCK(); 16754359Sroberto } 16854359Sroberto} 16954359Sroberto 170182007Sroberto 17154359Srobertovoid 172182007Srobertoadd_full_recv_buffer(recvbuf_t *rb) 17354359Sroberto{ 174182007Sroberto if (rb == NULL) { 175182007Sroberto msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); 176182007Sroberto return; 177182007Sroberto } 178182007Sroberto LOCK(); 179285612Sdelphij LINK_FIFO(full_recv_fifo, rb, link); 180182007Sroberto full_recvbufs++; 181182007Sroberto UNLOCK(); 18254359Sroberto} 18354359Sroberto 184285612Sdelphij 185182007Srobertorecvbuf_t * 186182007Srobertoget_free_recv_buffer(void) 18754359Sroberto{ 188285612Sdelphij recvbuf_t *buffer; 189285612Sdelphij 190182007Sroberto LOCK(); 191285612Sdelphij UNLINK_HEAD_SLIST(buffer, free_recv_list, link); 192285612Sdelphij if (buffer != NULL) { 193182007Sroberto free_recvbufs--; 194182007Sroberto initialise_buffer(buffer); 195285612Sdelphij buffer->used++; 196285612Sdelphij } else { 197182007Sroberto buffer_shortfall++; 19854359Sroberto } 199182007Sroberto UNLOCK(); 200285612Sdelphij 201285612Sdelphij return buffer; 20254359Sroberto} 20354359Sroberto 204285612Sdelphij 205182007Sroberto#ifdef HAVE_IO_COMPLETION_PORT 206182007Srobertorecvbuf_t * 207182007Srobertoget_free_recv_buffer_alloc(void) 20854359Sroberto{ 209285612Sdelphij recvbuf_t *buffer; 210285612Sdelphij 211285612Sdelphij buffer = get_free_recv_buffer(); 212285612Sdelphij if (NULL == buffer) { 213182007Sroberto create_buffers(RECV_INC); 214182007Sroberto buffer = get_free_recv_buffer(); 21554359Sroberto } 216289997Sglebius ENSURE(buffer != NULL); 217182007Sroberto return (buffer); 21854359Sroberto} 219182007Sroberto#endif 22054359Sroberto 221285612Sdelphij 222182007Srobertorecvbuf_t * 22354359Srobertoget_full_recv_buffer(void) 22454359Sroberto{ 225285612Sdelphij recvbuf_t * rbuf; 226285612Sdelphij 227182007Sroberto LOCK(); 228182007Sroberto 229182007Sroberto#ifdef HAVE_SIGNALED_IO 230182007Sroberto /* 231182007Sroberto * make sure there are free buffers when we 232285612Sdelphij * wander off to do lengthy packet processing with 233182007Sroberto * any buffer we grab from the full list. 234182007Sroberto * 235182007Sroberto * fixes malloc() interrupted by SIGIO risk 236182007Sroberto * (Bug 889) 237182007Sroberto */ 238285612Sdelphij if (NULL == free_recv_list || buffer_shortfall > 0) { 239182007Sroberto /* 240182007Sroberto * try to get us some more buffers 241182007Sroberto */ 242182007Sroberto create_buffers(RECV_INC); 243182007Sroberto } 244182007Sroberto#endif 245182007Sroberto 246182007Sroberto /* 247182007Sroberto * try to grab a full buffer 248182007Sroberto */ 249285612Sdelphij UNLINK_FIFO(rbuf, full_recv_fifo, link); 250182007Sroberto if (rbuf != NULL) 251285612Sdelphij full_recvbufs--; 252285612Sdelphij UNLOCK(); 253285612Sdelphij 254285612Sdelphij return rbuf; 255285612Sdelphij} 256285612Sdelphij 257285612Sdelphij 258285612Sdelphij/* 259285612Sdelphij * purge_recv_buffers_for_fd() - purges any previously-received input 260285612Sdelphij * from a given file descriptor. 261285612Sdelphij */ 262285612Sdelphijvoid 263285612Sdelphijpurge_recv_buffers_for_fd( 264298699Sdelphij int fd 265285612Sdelphij ) 266285612Sdelphij{ 267285612Sdelphij recvbuf_t *rbufp; 268285612Sdelphij recvbuf_t *next; 269285612Sdelphij recvbuf_t *punlinked; 270285612Sdelphij 271285612Sdelphij LOCK(); 272285612Sdelphij 273285612Sdelphij for (rbufp = HEAD_FIFO(full_recv_fifo); 274285612Sdelphij rbufp != NULL; 275285612Sdelphij rbufp = next) { 276285612Sdelphij next = rbufp->link; 277298699Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 278298699Sdelphij if (rbufp->dstadr == NULL && rbufp->fd == fd) 279298699Sdelphij# else 280298699Sdelphij if (rbufp->fd == fd) 281298699Sdelphij# endif 282298699Sdelphij { 283285612Sdelphij UNLINK_MID_FIFO(punlinked, full_recv_fifo, 284285612Sdelphij rbufp, link, recvbuf_t); 285285612Sdelphij INSIST(punlinked == rbufp); 286285612Sdelphij full_recvbufs--; 287285612Sdelphij freerecvbuf(rbufp); 288285612Sdelphij } 28954359Sroberto } 290285612Sdelphij 291182007Sroberto UNLOCK(); 29254359Sroberto} 293182007Sroberto 294285612Sdelphij 295182007Sroberto/* 296182007Sroberto * Checks to see if there are buffers to process 297182007Sroberto */ 298182007Srobertoisc_boolean_t has_full_recv_buffer(void) 299182007Sroberto{ 300285612Sdelphij if (HEAD_FIFO(full_recv_fifo) != NULL) 301182007Sroberto return (ISC_TRUE); 302182007Sroberto else 303182007Sroberto return (ISC_FALSE); 304182007Sroberto} 305285612Sdelphij 306285612Sdelphij 307285612Sdelphij#ifdef NTP_DEBUG_LISTS_H 308285612Sdelphijvoid 309285612Sdelphijcheck_gen_fifo_consistency(void *fifo) 310285612Sdelphij{ 311285612Sdelphij gen_fifo *pf; 312285612Sdelphij gen_node *pthis; 313285612Sdelphij gen_node **pptail; 314285612Sdelphij 315285612Sdelphij pf = fifo; 316285612Sdelphij REQUIRE((NULL == pf->phead && NULL == pf->pptail) || 317285612Sdelphij (NULL != pf->phead && NULL != pf->pptail)); 318285612Sdelphij 319285612Sdelphij pptail = &pf->phead; 320285612Sdelphij for (pthis = pf->phead; 321285612Sdelphij pthis != NULL; 322285612Sdelphij pthis = pthis->link) 323285612Sdelphij if (NULL != pthis->link) 324285612Sdelphij pptail = &pthis->link; 325285612Sdelphij 326285612Sdelphij REQUIRE(NULL == pf->pptail || pptail == pf->pptail); 327285612Sdelphij} 328285612Sdelphij#endif /* NTP_DEBUG_LISTS_H */ 329