1c0b746e5SOllivier Robert #ifdef HAVE_CONFIG_H 2c0b746e5SOllivier Robert # include <config.h> 3c0b746e5SOllivier Robert #endif 4c0b746e5SOllivier Robert 5c0b746e5SOllivier Robert #include <stdio.h> 62b15cb3dSCy Schubert 72b15cb3dSCy Schubert #include "ntp_assert.h" 8c0b746e5SOllivier Robert #include "ntp_syslog.h" 9224ba2bdSOllivier Robert #include "ntp_stdlib.h" 102b15cb3dSCy Schubert #include "ntp_lists.h" 11c0b746e5SOllivier Robert #include "recvbuff.h" 12c0b746e5SOllivier Robert #include "iosignal.h" 13c0b746e5SOllivier Robert 14*767173ceSCy Schubert #if (RECV_INC & (RECV_INC-1)) 15*767173ceSCy Schubert # error RECV_INC not a power of 2! 16*767173ceSCy Schubert #endif 17*767173ceSCy Schubert #if (RECV_BATCH & (RECV_BATCH - 1)) 18*767173ceSCy Schubert #error RECV_BATCH not a power of 2! 19*767173ceSCy Schubert #endif 20*767173ceSCy Schubert #if (RECV_BATCH < RECV_INC) 21*767173ceSCy Schubert #error RECV_BATCH must be >= RECV_INC! 22*767173ceSCy Schubert #endif 232b15cb3dSCy Schubert 24c0b746e5SOllivier Robert /* 25c0b746e5SOllivier Robert * Memory allocation 26c0b746e5SOllivier Robert */ 272b15cb3dSCy Schubert static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ 282b15cb3dSCy Schubert static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */ 29c0b746e5SOllivier Robert static u_long volatile total_recvbufs; /* total recvbufs currently in use */ 30c0b746e5SOllivier Robert static u_long volatile lowater_adds; /* number of times we have added memory */ 31ea906c41SOllivier Robert static u_long volatile buffer_shortfall;/* number of missed free receive buffers 32ea906c41SOllivier Robert between replenishments */ 33*767173ceSCy Schubert static u_long limit_recvbufs; /* maximum total of receive buffers */ 34*767173ceSCy Schubert static u_long emerg_recvbufs; /* emergency/urgent buffers to keep */ 35c0b746e5SOllivier Robert 362b15cb3dSCy Schubert static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; 372b15cb3dSCy Schubert static recvbuf_t * free_recv_list; 38c0b746e5SOllivier Robert 39ea906c41SOllivier Robert #if defined(SYS_WINNT) 40ea906c41SOllivier Robert 41ea906c41SOllivier Robert /* 42ea906c41SOllivier Robert * For Windows we need to set up a lock to manipulate the 43ea906c41SOllivier Robert * recv buffers to prevent corruption. We keep it lock for as 44ea906c41SOllivier Robert * short a time as possible 45ea906c41SOllivier Robert */ 46ea906c41SOllivier Robert static CRITICAL_SECTION RecvLock; 47*767173ceSCy Schubert static CRITICAL_SECTION FreeLock; 48*767173ceSCy Schubert # define LOCK_R() EnterCriticalSection(&RecvLock) 49*767173ceSCy Schubert # define UNLOCK_R() LeaveCriticalSection(&RecvLock) 50*767173ceSCy Schubert # define LOCK_F() EnterCriticalSection(&FreeLock) 51*767173ceSCy Schubert # define UNLOCK_F() LeaveCriticalSection(&FreeLock) 52c0b746e5SOllivier Robert #else 53*767173ceSCy Schubert # define LOCK_R() do {} while (FALSE) 54*767173ceSCy Schubert # define UNLOCK_R() do {} while (FALSE) 55*767173ceSCy Schubert # define LOCK_F() do {} while (FALSE) 56*767173ceSCy Schubert # define UNLOCK_F() do {} while (FALSE) 57c0b746e5SOllivier Robert #endif 58c0b746e5SOllivier Robert 592b15cb3dSCy Schubert #ifdef DEBUG 602b15cb3dSCy Schubert static void uninit_recvbuff(void); 612b15cb3dSCy Schubert #endif 622b15cb3dSCy Schubert 632b15cb3dSCy Schubert 64c0b746e5SOllivier Robert u_long 65c0b746e5SOllivier Robert free_recvbuffs (void) 66c0b746e5SOllivier Robert { 67c0b746e5SOllivier Robert return free_recvbufs; 68c0b746e5SOllivier Robert } 69c0b746e5SOllivier Robert 70c0b746e5SOllivier Robert u_long 71c0b746e5SOllivier Robert full_recvbuffs (void) 72c0b746e5SOllivier Robert { 73ea906c41SOllivier Robert return full_recvbufs; 74c0b746e5SOllivier Robert } 75c0b746e5SOllivier Robert 76c0b746e5SOllivier Robert u_long 77c0b746e5SOllivier Robert total_recvbuffs (void) 78c0b746e5SOllivier Robert { 79ea906c41SOllivier Robert return total_recvbufs; 80c0b746e5SOllivier Robert } 81c0b746e5SOllivier Robert 82c0b746e5SOllivier Robert u_long 83c0b746e5SOllivier Robert lowater_additions(void) 84c0b746e5SOllivier Robert { 85c0b746e5SOllivier Robert return lowater_adds; 86c0b746e5SOllivier Robert } 87c0b746e5SOllivier Robert 882b15cb3dSCy Schubert static inline void 89ea906c41SOllivier Robert initialise_buffer(recvbuf_t *buff) 90c0b746e5SOllivier Robert { 912b15cb3dSCy Schubert ZERO(*buff); 92c0b746e5SOllivier Robert } 93c0b746e5SOllivier Robert 94c0b746e5SOllivier Robert static void 95*767173ceSCy Schubert create_buffers( 96*767173ceSCy Schubert size_t nbufs) 97c0b746e5SOllivier Robert { 98*767173ceSCy Schubert # ifndef DEBUG 99*767173ceSCy Schubert static const u_int chunk = RECV_INC; 100*767173ceSCy Schubert # else 101*767173ceSCy Schubert /* Allocate each buffer individually so they can be free()d 102*767173ceSCy Schubert * during ntpd shutdown on DEBUG builds to keep them out of heap 103*767173ceSCy Schubert * leak reports. 104*767173ceSCy Schubert */ 105*767173ceSCy Schubert static const u_int chunk = 1; 106*767173ceSCy Schubert # endif 107*767173ceSCy Schubert 108ea906c41SOllivier Robert register recvbuf_t *bufp; 109*767173ceSCy Schubert u_int i; 110*767173ceSCy Schubert size_t abuf; 111*767173ceSCy Schubert 112*767173ceSCy Schubert if (limit_recvbufs <= total_recvbufs) 113*767173ceSCy Schubert return; 114c0b746e5SOllivier Robert 115ea906c41SOllivier Robert abuf = nbufs + buffer_shortfall; 116ea906c41SOllivier Robert buffer_shortfall = 0; 117ea906c41SOllivier Robert 118*767173ceSCy Schubert if (abuf < nbufs || abuf > RECV_BATCH) 119*767173ceSCy Schubert abuf = RECV_BATCH; /* clamp on overflow */ 120*767173ceSCy Schubert else 121*767173ceSCy Schubert abuf += (~abuf + 1) & (RECV_INC - 1); /* round up */ 122ea906c41SOllivier Robert 123*767173ceSCy Schubert if (abuf > (limit_recvbufs - total_recvbufs)) 124*767173ceSCy Schubert abuf = limit_recvbufs - total_recvbufs; 125*767173ceSCy Schubert abuf += (~abuf + 1) & (chunk - 1); /* round up */ 126*767173ceSCy Schubert 127*767173ceSCy Schubert while (abuf) { 128*767173ceSCy Schubert bufp = calloc(chunk, sizeof(*bufp)); 129*767173ceSCy Schubert if (!bufp) { 130*767173ceSCy Schubert limit_recvbufs = total_recvbufs; 131*767173ceSCy Schubert break; 132ea906c41SOllivier Robert } 133*767173ceSCy Schubert for (i = chunk; i; --i,++bufp) { 134*767173ceSCy Schubert LINK_SLIST(free_recv_list, bufp, link); 135*767173ceSCy Schubert } 136*767173ceSCy Schubert free_recvbufs += chunk; 137*767173ceSCy Schubert total_recvbufs += chunk; 138*767173ceSCy Schubert abuf -= chunk; 139*767173ceSCy Schubert } 140*767173ceSCy Schubert ++lowater_adds; 141c0b746e5SOllivier Robert } 142c0b746e5SOllivier Robert 143c0b746e5SOllivier Robert void 144c0b746e5SOllivier Robert init_recvbuff(int nbufs) 145c0b746e5SOllivier Robert { 146c0b746e5SOllivier Robert 147c0b746e5SOllivier Robert /* 148c0b746e5SOllivier Robert * Init buffer free list and stat counters 149c0b746e5SOllivier Robert */ 150ea906c41SOllivier Robert free_recvbufs = total_recvbufs = 0; 151c0b746e5SOllivier Robert full_recvbufs = lowater_adds = 0; 152c0b746e5SOllivier Robert 153*767173ceSCy Schubert limit_recvbufs = RECV_TOOMANY; 154*767173ceSCy Schubert emerg_recvbufs = RECV_CLOCK; 155*767173ceSCy Schubert 156ea906c41SOllivier Robert create_buffers(nbufs); 157ea906c41SOllivier Robert 158ea906c41SOllivier Robert # if defined(SYS_WINNT) 159ea906c41SOllivier Robert InitializeCriticalSection(&RecvLock); 160*767173ceSCy Schubert InitializeCriticalSection(&FreeLock); 161c0b746e5SOllivier Robert # endif 162c0b746e5SOllivier Robert 1632b15cb3dSCy Schubert # ifdef DEBUG 1642b15cb3dSCy Schubert atexit(&uninit_recvbuff); 1652b15cb3dSCy Schubert # endif 166c0b746e5SOllivier Robert } 167c0b746e5SOllivier Robert 1682b15cb3dSCy Schubert 1692b15cb3dSCy Schubert #ifdef DEBUG 1702b15cb3dSCy Schubert static void 1712b15cb3dSCy Schubert uninit_recvbuff(void) 1722b15cb3dSCy Schubert { 1732b15cb3dSCy Schubert recvbuf_t *rbunlinked; 1742b15cb3dSCy Schubert 1752b15cb3dSCy Schubert for (;;) { 1762b15cb3dSCy Schubert UNLINK_FIFO(rbunlinked, full_recv_fifo, link); 1772b15cb3dSCy Schubert if (rbunlinked == NULL) 1782b15cb3dSCy Schubert break; 1792b15cb3dSCy Schubert free(rbunlinked); 1802b15cb3dSCy Schubert } 1812b15cb3dSCy Schubert 1822b15cb3dSCy Schubert for (;;) { 1832b15cb3dSCy Schubert UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); 1842b15cb3dSCy Schubert if (rbunlinked == NULL) 1852b15cb3dSCy Schubert break; 1862b15cb3dSCy Schubert free(rbunlinked); 1872b15cb3dSCy Schubert } 188*767173ceSCy Schubert # if defined(SYS_WINNT) 189*767173ceSCy Schubert DeleteCriticalSection(&FreeLock); 190*767173ceSCy Schubert DeleteCriticalSection(&RecvLock); 191*767173ceSCy Schubert # endif 1922b15cb3dSCy Schubert } 1932b15cb3dSCy Schubert #endif /* DEBUG */ 1942b15cb3dSCy Schubert 1952b15cb3dSCy Schubert 196c0b746e5SOllivier Robert /* 197c0b746e5SOllivier Robert * freerecvbuf - make a single recvbuf available for reuse 198c0b746e5SOllivier Robert */ 199c0b746e5SOllivier Robert void 200ea906c41SOllivier Robert freerecvbuf(recvbuf_t *rb) 201c0b746e5SOllivier Robert { 2024990d495SXin LI if (rb) { 203*767173ceSCy Schubert if (--rb->used != 0) { 204ea906c41SOllivier Robert msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 205*767173ceSCy Schubert rb->used = 0; 206*767173ceSCy Schubert } 207*767173ceSCy Schubert LOCK_F(); 2082b15cb3dSCy Schubert LINK_SLIST(free_recv_list, rb, link); 209*767173ceSCy Schubert ++free_recvbufs; 210*767173ceSCy Schubert UNLOCK_F(); 211c0b746e5SOllivier Robert } 2124990d495SXin LI } 213c0b746e5SOllivier Robert 214c0b746e5SOllivier Robert 215c0b746e5SOllivier Robert void 216ea906c41SOllivier Robert add_full_recv_buffer(recvbuf_t *rb) 217c0b746e5SOllivier Robert { 218ea906c41SOllivier Robert if (rb == NULL) { 219ea906c41SOllivier Robert msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); 220ea906c41SOllivier Robert return; 221c0b746e5SOllivier Robert } 222*767173ceSCy Schubert LOCK_R(); 2232b15cb3dSCy Schubert LINK_FIFO(full_recv_fifo, rb, link); 224*767173ceSCy Schubert ++full_recvbufs; 225*767173ceSCy Schubert UNLOCK_R(); 226c0b746e5SOllivier Robert } 227c0b746e5SOllivier Robert 2282b15cb3dSCy Schubert 229ea906c41SOllivier Robert recvbuf_t * 230*767173ceSCy Schubert get_free_recv_buffer( 231*767173ceSCy Schubert int /*BOOL*/ urgent 232*767173ceSCy Schubert ) 233c0b746e5SOllivier Robert { 234*767173ceSCy Schubert recvbuf_t *buffer = NULL; 2352b15cb3dSCy Schubert 236*767173ceSCy Schubert LOCK_F(); 237*767173ceSCy Schubert if (free_recvbufs > (urgent ? emerg_recvbufs : 0)) { 2382b15cb3dSCy Schubert UNLINK_HEAD_SLIST(buffer, free_recv_list, link); 239c0b746e5SOllivier Robert } 240*767173ceSCy Schubert 241*767173ceSCy Schubert if (buffer != NULL) { 242*767173ceSCy Schubert if (free_recvbufs) 243*767173ceSCy Schubert --free_recvbufs; 244*767173ceSCy Schubert initialise_buffer(buffer); 245*767173ceSCy Schubert ++buffer->used; 246*767173ceSCy Schubert } else { 247*767173ceSCy Schubert ++buffer_shortfall; 248*767173ceSCy Schubert } 249*767173ceSCy Schubert UNLOCK_F(); 2502b15cb3dSCy Schubert 2512b15cb3dSCy Schubert return buffer; 252c0b746e5SOllivier Robert } 253c0b746e5SOllivier Robert 2542b15cb3dSCy Schubert 255ea906c41SOllivier Robert #ifdef HAVE_IO_COMPLETION_PORT 256ea906c41SOllivier Robert recvbuf_t * 257*767173ceSCy Schubert get_free_recv_buffer_alloc( 258*767173ceSCy Schubert int /*BOOL*/ urgent 259*767173ceSCy Schubert ) 260c0b746e5SOllivier Robert { 261*767173ceSCy Schubert LOCK_F(); 262*767173ceSCy Schubert if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0) 263ea906c41SOllivier Robert create_buffers(RECV_INC); 264*767173ceSCy Schubert UNLOCK_F(); 265*767173ceSCy Schubert return get_free_recv_buffer(urgent); 266c0b746e5SOllivier Robert } 267ea906c41SOllivier Robert #endif 268c0b746e5SOllivier Robert 2692b15cb3dSCy Schubert 270ea906c41SOllivier Robert recvbuf_t * 271c0b746e5SOllivier Robert get_full_recv_buffer(void) 272c0b746e5SOllivier Robert { 273ea906c41SOllivier Robert recvbuf_t * rbuf; 2742b15cb3dSCy Schubert 275ea906c41SOllivier Robert /* 276*767173ceSCy Schubert * make sure there are free buffers when we wander off to do 277*767173ceSCy Schubert * lengthy packet processing with any buffer we grab from the 278*767173ceSCy Schubert * full list. 279ea906c41SOllivier Robert * 280*767173ceSCy Schubert * fixes malloc() interrupted by SIGIO risk (Bug 889) 281ea906c41SOllivier Robert */ 282*767173ceSCy Schubert LOCK_F(); 283*767173ceSCy Schubert if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0) 284ea906c41SOllivier Robert create_buffers(RECV_INC); 285*767173ceSCy Schubert UNLOCK_F(); 286ea906c41SOllivier Robert 287ea906c41SOllivier Robert /* 288ea906c41SOllivier Robert * try to grab a full buffer 289ea906c41SOllivier Robert */ 290*767173ceSCy Schubert LOCK_R(); 2912b15cb3dSCy Schubert UNLINK_FIFO(rbuf, full_recv_fifo, link); 292*767173ceSCy Schubert if (rbuf != NULL && full_recvbufs) 293*767173ceSCy Schubert --full_recvbufs; 294*767173ceSCy Schubert UNLOCK_R(); 2952b15cb3dSCy Schubert 2962b15cb3dSCy Schubert return rbuf; 297ea906c41SOllivier Robert } 298ea906c41SOllivier Robert 2992b15cb3dSCy Schubert 3002b15cb3dSCy Schubert /* 3012b15cb3dSCy Schubert * purge_recv_buffers_for_fd() - purges any previously-received input 3022b15cb3dSCy Schubert * from a given file descriptor. 3032b15cb3dSCy Schubert */ 3042b15cb3dSCy Schubert void 3052b15cb3dSCy Schubert purge_recv_buffers_for_fd( 3064990d495SXin LI int fd 3072b15cb3dSCy Schubert ) 3082b15cb3dSCy Schubert { 3092b15cb3dSCy Schubert recvbuf_t *rbufp; 3102b15cb3dSCy Schubert recvbuf_t *next; 3112b15cb3dSCy Schubert recvbuf_t *punlinked; 312*767173ceSCy Schubert recvbuf_t *freelist = NULL; 3132b15cb3dSCy Schubert 314*767173ceSCy Schubert /* We want to hold only one lock at a time. So we do a scan on 315*767173ceSCy Schubert * the full buffer queue, collecting items as we go, and when 316*767173ceSCy Schubert * done we spool the the collected items to 'freerecvbuf()'. 317*767173ceSCy Schubert */ 318*767173ceSCy Schubert LOCK_R(); 3192b15cb3dSCy Schubert 3202b15cb3dSCy Schubert for (rbufp = HEAD_FIFO(full_recv_fifo); 3212b15cb3dSCy Schubert rbufp != NULL; 322*767173ceSCy Schubert rbufp = next) 323*767173ceSCy Schubert { 3242b15cb3dSCy Schubert next = rbufp->link; 3254990d495SXin LI # ifdef HAVE_IO_COMPLETION_PORT 3264990d495SXin LI if (rbufp->dstadr == NULL && rbufp->fd == fd) 3274990d495SXin LI # else 3284990d495SXin LI if (rbufp->fd == fd) 3294990d495SXin LI # endif 3304990d495SXin LI { 3312b15cb3dSCy Schubert UNLINK_MID_FIFO(punlinked, full_recv_fifo, 3322b15cb3dSCy Schubert rbufp, link, recvbuf_t); 3332b15cb3dSCy Schubert INSIST(punlinked == rbufp); 334*767173ceSCy Schubert if (full_recvbufs) 335*767173ceSCy Schubert --full_recvbufs; 336*767173ceSCy Schubert rbufp->link = freelist; 337*767173ceSCy Schubert freelist = rbufp; 3382b15cb3dSCy Schubert } 3392b15cb3dSCy Schubert } 3402b15cb3dSCy Schubert 341*767173ceSCy Schubert UNLOCK_R(); 342*767173ceSCy Schubert 343*767173ceSCy Schubert while (freelist) { 344*767173ceSCy Schubert next = freelist->link; 345*767173ceSCy Schubert freerecvbuf(freelist); 346*767173ceSCy Schubert freelist = next; 347*767173ceSCy Schubert } 3482b15cb3dSCy Schubert } 3492b15cb3dSCy Schubert 3502b15cb3dSCy Schubert 351ea906c41SOllivier Robert /* 352ea906c41SOllivier Robert * Checks to see if there are buffers to process 353ea906c41SOllivier Robert */ 354ea906c41SOllivier Robert isc_boolean_t has_full_recv_buffer(void) 355ea906c41SOllivier Robert { 3562b15cb3dSCy Schubert if (HEAD_FIFO(full_recv_fifo) != NULL) 357ea906c41SOllivier Robert return (ISC_TRUE); 358ea906c41SOllivier Robert else 359ea906c41SOllivier Robert return (ISC_FALSE); 360c0b746e5SOllivier Robert } 3612b15cb3dSCy Schubert 3622b15cb3dSCy Schubert 3632b15cb3dSCy Schubert #ifdef NTP_DEBUG_LISTS_H 3642b15cb3dSCy Schubert void 3652b15cb3dSCy Schubert check_gen_fifo_consistency(void *fifo) 3662b15cb3dSCy Schubert { 3672b15cb3dSCy Schubert gen_fifo *pf; 3682b15cb3dSCy Schubert gen_node *pthis; 3692b15cb3dSCy Schubert gen_node **pptail; 3702b15cb3dSCy Schubert 3712b15cb3dSCy Schubert pf = fifo; 3722b15cb3dSCy Schubert REQUIRE((NULL == pf->phead && NULL == pf->pptail) || 3732b15cb3dSCy Schubert (NULL != pf->phead && NULL != pf->pptail)); 3742b15cb3dSCy Schubert 3752b15cb3dSCy Schubert pptail = &pf->phead; 3762b15cb3dSCy Schubert for (pthis = pf->phead; 3772b15cb3dSCy Schubert pthis != NULL; 3782b15cb3dSCy Schubert pthis = pthis->link) 3792b15cb3dSCy Schubert if (NULL != pthis->link) 3802b15cb3dSCy Schubert pptail = &pthis->link; 3812b15cb3dSCy Schubert 3822b15cb3dSCy Schubert REQUIRE(NULL == pf->pptail || pptail == pf->pptail); 3832b15cb3dSCy Schubert } 3842b15cb3dSCy Schubert #endif /* NTP_DEBUG_LISTS_H */ 385