154359Sroberto#ifdef HAVE_CONFIG_H 254359Sroberto# include <config.h> 354359Sroberto#endif 454359Sroberto 554359Sroberto#include <stdio.h> 6290001Sglebius 7290001Sglebius#include "ntp_assert.h" 882498Sroberto#include "ntp_syslog.h" 954359Sroberto#include "ntp_stdlib.h" 10290001Sglebius#include "ntp_lists.h" 1154359Sroberto#include "recvbuff.h" 1254359Sroberto#include "iosignal.h" 1354359Sroberto 14290001Sglebius 1554359Sroberto/* 1654359Sroberto * Memory allocation 1754359Sroberto */ 18290001Sglebiusstatic u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ 19290001Sglebiusstatic 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 23290001Sglebius between replenishments */ 2454359Sroberto 25290001Sglebiusstatic DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; 26290001Sglebiusstatic 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 39290001Sglebius# define LOCK() do {} while (FALSE) 40290001Sglebius# define UNLOCK() do {} while (FALSE) 4154359Sroberto#endif 4254359Sroberto 43290001Sglebius#ifdef DEBUG 44290001Sglebiusstatic void uninit_recvbuff(void); 45290001Sglebius#endif 46290001Sglebius 47290001Sglebius 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 72290001Sglebiusstatic inline void 73182007Srobertoinitialise_buffer(recvbuf_t *buff) 7454359Sroberto{ 75290001Sglebius 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 87290001Sglebius#ifndef DEBUG 88290001Sglebius bufp = emalloc_zero(abuf * sizeof(*bufp)); 89290001Sglebius#endif 90182007Sroberto 91290001Sglebius for (i = 0; i < abuf; i++) { 92290001Sglebius#ifdef DEBUG 93290001Sglebius /* 94290001Sglebius * Allocate each buffer individually so they can be 95290001Sglebius * free()d during ntpd shutdown on DEBUG builds to 96290001Sglebius * keep them out of heap leak reports. 97290001Sglebius */ 98290001Sglebius bufp = emalloc_zero(sizeof(*bufp)); 99290001Sglebius#endif 100290001Sglebius 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 124290001Sglebius#ifdef DEBUG 125290001Sglebius atexit(&uninit_recvbuff); 126290001Sglebius#endif 12754359Sroberto} 12854359Sroberto 129290001Sglebius 130290001Sglebius#ifdef DEBUG 131290001Sglebiusstatic void 132290001Sglebiusuninit_recvbuff(void) 133290001Sglebius{ 134290001Sglebius recvbuf_t *rbunlinked; 135290001Sglebius 136290001Sglebius for (;;) { 137290001Sglebius UNLINK_FIFO(rbunlinked, full_recv_fifo, link); 138290001Sglebius if (rbunlinked == NULL) 139290001Sglebius break; 140290001Sglebius free(rbunlinked); 141290001Sglebius } 142290001Sglebius 143290001Sglebius for (;;) { 144290001Sglebius UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); 145290001Sglebius if (rbunlinked == NULL) 146290001Sglebius break; 147290001Sglebius free(rbunlinked); 148290001Sglebius } 149290001Sglebius} 150290001Sglebius#endif /* DEBUG */ 151290001Sglebius 152290001Sglebius 15354359Sroberto/* 154182007Sroberto * freerecvbuf - make a single recvbuf available for reuse 15554359Sroberto */ 156182007Srobertovoid 157182007Srobertofreerecvbuf(recvbuf_t *rb) 15854359Sroberto{ 159298770Sdelphij if (rb) { 160298770Sdelphij LOCK(); 161298770Sdelphij rb->used--; 162298770Sdelphij if (rb->used != 0) 163298770Sdelphij msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 164298770Sdelphij LINK_SLIST(free_recv_list, rb, link); 165298770Sdelphij free_recvbufs++; 166298770Sdelphij 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(); 179290001Sglebius LINK_FIFO(full_recv_fifo, rb, link); 180182007Sroberto full_recvbufs++; 181182007Sroberto UNLOCK(); 18254359Sroberto} 18354359Sroberto 184290001Sglebius 185182007Srobertorecvbuf_t * 186182007Srobertoget_free_recv_buffer(void) 18754359Sroberto{ 188290001Sglebius recvbuf_t *buffer; 189290001Sglebius 190182007Sroberto LOCK(); 191290001Sglebius UNLINK_HEAD_SLIST(buffer, free_recv_list, link); 192290001Sglebius if (buffer != NULL) { 193182007Sroberto free_recvbufs--; 194182007Sroberto initialise_buffer(buffer); 195290001Sglebius buffer->used++; 196290001Sglebius } else { 197182007Sroberto buffer_shortfall++; 19854359Sroberto } 199182007Sroberto UNLOCK(); 200290001Sglebius 201290001Sglebius return buffer; 20254359Sroberto} 20354359Sroberto 204290001Sglebius 205182007Sroberto#ifdef HAVE_IO_COMPLETION_PORT 206182007Srobertorecvbuf_t * 207182007Srobertoget_free_recv_buffer_alloc(void) 20854359Sroberto{ 209290001Sglebius recvbuf_t *buffer; 210290001Sglebius 211290001Sglebius buffer = get_free_recv_buffer(); 212290001Sglebius if (NULL == buffer) { 213182007Sroberto create_buffers(RECV_INC); 214182007Sroberto buffer = get_free_recv_buffer(); 21554359Sroberto } 216290001Sglebius ENSURE(buffer != NULL); 217182007Sroberto return (buffer); 21854359Sroberto} 219182007Sroberto#endif 22054359Sroberto 221290001Sglebius 222182007Srobertorecvbuf_t * 22354359Srobertoget_full_recv_buffer(void) 22454359Sroberto{ 225290001Sglebius recvbuf_t * rbuf; 226290001Sglebius 227182007Sroberto LOCK(); 228182007Sroberto 229182007Sroberto#ifdef HAVE_SIGNALED_IO 230182007Sroberto /* 231182007Sroberto * make sure there are free buffers when we 232290001Sglebius * 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 */ 238290001Sglebius 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 */ 249290001Sglebius UNLINK_FIFO(rbuf, full_recv_fifo, link); 250182007Sroberto if (rbuf != NULL) 251290001Sglebius full_recvbufs--; 252290001Sglebius UNLOCK(); 253290001Sglebius 254290001Sglebius return rbuf; 255290001Sglebius} 256290001Sglebius 257290001Sglebius 258290001Sglebius/* 259290001Sglebius * purge_recv_buffers_for_fd() - purges any previously-received input 260290001Sglebius * from a given file descriptor. 261290001Sglebius */ 262290001Sglebiusvoid 263290001Sglebiuspurge_recv_buffers_for_fd( 264298770Sdelphij int fd 265290001Sglebius ) 266290001Sglebius{ 267290001Sglebius recvbuf_t *rbufp; 268290001Sglebius recvbuf_t *next; 269290001Sglebius recvbuf_t *punlinked; 270290001Sglebius 271290001Sglebius LOCK(); 272290001Sglebius 273290001Sglebius for (rbufp = HEAD_FIFO(full_recv_fifo); 274290001Sglebius rbufp != NULL; 275290001Sglebius rbufp = next) { 276290001Sglebius next = rbufp->link; 277298770Sdelphij# ifdef HAVE_IO_COMPLETION_PORT 278298770Sdelphij if (rbufp->dstadr == NULL && rbufp->fd == fd) 279298770Sdelphij# else 280298770Sdelphij if (rbufp->fd == fd) 281298770Sdelphij# endif 282298770Sdelphij { 283290001Sglebius UNLINK_MID_FIFO(punlinked, full_recv_fifo, 284290001Sglebius rbufp, link, recvbuf_t); 285290001Sglebius INSIST(punlinked == rbufp); 286290001Sglebius full_recvbufs--; 287290001Sglebius freerecvbuf(rbufp); 288290001Sglebius } 28954359Sroberto } 290290001Sglebius 291182007Sroberto UNLOCK(); 29254359Sroberto} 293182007Sroberto 294290001Sglebius 295182007Sroberto/* 296182007Sroberto * Checks to see if there are buffers to process 297182007Sroberto */ 298182007Srobertoisc_boolean_t has_full_recv_buffer(void) 299182007Sroberto{ 300290001Sglebius if (HEAD_FIFO(full_recv_fifo) != NULL) 301182007Sroberto return (ISC_TRUE); 302182007Sroberto else 303182007Sroberto return (ISC_FALSE); 304182007Sroberto} 305290001Sglebius 306290001Sglebius 307290001Sglebius#ifdef NTP_DEBUG_LISTS_H 308290001Sglebiusvoid 309290001Sglebiuscheck_gen_fifo_consistency(void *fifo) 310290001Sglebius{ 311290001Sglebius gen_fifo *pf; 312290001Sglebius gen_node *pthis; 313290001Sglebius gen_node **pptail; 314290001Sglebius 315290001Sglebius pf = fifo; 316290001Sglebius REQUIRE((NULL == pf->phead && NULL == pf->pptail) || 317290001Sglebius (NULL != pf->phead && NULL != pf->pptail)); 318290001Sglebius 319290001Sglebius pptail = &pf->phead; 320290001Sglebius for (pthis = pf->phead; 321290001Sglebius pthis != NULL; 322290001Sglebius pthis = pthis->link) 323290001Sglebius if (NULL != pthis->link) 324290001Sglebius pptail = &pthis->link; 325290001Sglebius 326290001Sglebius REQUIRE(NULL == pf->pptail || pptail == pf->pptail); 327290001Sglebius} 328290001Sglebius#endif /* NTP_DEBUG_LISTS_H */ 329