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 14767173ceSCy Schubert #if (RECV_INC & (RECV_INC-1)) 15767173ceSCy Schubert # error RECV_INC not a power of 2! 16767173ceSCy Schubert #endif 17767173ceSCy Schubert #if (RECV_BATCH & (RECV_BATCH - 1)) 18767173ceSCy Schubert #error RECV_BATCH not a power of 2! 19767173ceSCy Schubert #endif 20767173ceSCy Schubert #if (RECV_BATCH < RECV_INC) 21767173ceSCy Schubert #error RECV_BATCH must be >= RECV_INC! 22767173ceSCy 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 */ 33767173ceSCy Schubert static u_long limit_recvbufs; /* maximum total of receive buffers */ 34767173ceSCy 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; 47767173ceSCy Schubert static CRITICAL_SECTION FreeLock; 48767173ceSCy Schubert # define LOCK_R() EnterCriticalSection(&RecvLock) 49767173ceSCy Schubert # define UNLOCK_R() LeaveCriticalSection(&RecvLock) 50767173ceSCy Schubert # define LOCK_F() EnterCriticalSection(&FreeLock) 51767173ceSCy Schubert # define UNLOCK_F() LeaveCriticalSection(&FreeLock) 52c0b746e5SOllivier Robert #else 53767173ceSCy Schubert # define LOCK_R() do {} while (FALSE) 54767173ceSCy Schubert # define UNLOCK_R() do {} while (FALSE) 55767173ceSCy Schubert # define LOCK_F() do {} while (FALSE) 56767173ceSCy 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 95767173ceSCy Schubert create_buffers( 96767173ceSCy Schubert size_t nbufs) 97c0b746e5SOllivier Robert { 98767173ceSCy Schubert # ifndef DEBUG 99767173ceSCy Schubert static const u_int chunk = RECV_INC; 100767173ceSCy Schubert # else 101767173ceSCy Schubert /* Allocate each buffer individually so they can be free()d 102767173ceSCy Schubert * during ntpd shutdown on DEBUG builds to keep them out of heap 103767173ceSCy Schubert * leak reports. 104767173ceSCy Schubert */ 105767173ceSCy Schubert static const u_int chunk = 1; 106767173ceSCy Schubert # endif 107767173ceSCy Schubert 108ea906c41SOllivier Robert register recvbuf_t *bufp; 109767173ceSCy Schubert u_int i; 110767173ceSCy Schubert size_t abuf; 111767173ceSCy Schubert 112*a466cc55SCy Schubert /*[bug 3666]: followup -- reset shortfalls in all cases */ 113ea906c41SOllivier Robert abuf = nbufs + buffer_shortfall; 114ea906c41SOllivier Robert buffer_shortfall = 0; 115ea906c41SOllivier Robert 116*a466cc55SCy Schubert if (limit_recvbufs <= total_recvbufs) 117*a466cc55SCy Schubert return; 118*a466cc55SCy Schubert 119767173ceSCy Schubert if (abuf < nbufs || abuf > RECV_BATCH) 120767173ceSCy Schubert abuf = RECV_BATCH; /* clamp on overflow */ 121767173ceSCy Schubert else 122767173ceSCy Schubert abuf += (~abuf + 1) & (RECV_INC - 1); /* round up */ 123ea906c41SOllivier Robert 124767173ceSCy Schubert if (abuf > (limit_recvbufs - total_recvbufs)) 125767173ceSCy Schubert abuf = limit_recvbufs - total_recvbufs; 126767173ceSCy Schubert abuf += (~abuf + 1) & (chunk - 1); /* round up */ 127767173ceSCy Schubert 128767173ceSCy Schubert while (abuf) { 129767173ceSCy Schubert bufp = calloc(chunk, sizeof(*bufp)); 130767173ceSCy Schubert if (!bufp) { 131767173ceSCy Schubert limit_recvbufs = total_recvbufs; 132767173ceSCy Schubert break; 133ea906c41SOllivier Robert } 134767173ceSCy Schubert for (i = chunk; i; --i,++bufp) { 135767173ceSCy Schubert LINK_SLIST(free_recv_list, bufp, link); 136767173ceSCy Schubert } 137767173ceSCy Schubert free_recvbufs += chunk; 138767173ceSCy Schubert total_recvbufs += chunk; 139767173ceSCy Schubert abuf -= chunk; 140767173ceSCy Schubert } 141767173ceSCy Schubert ++lowater_adds; 142c0b746e5SOllivier Robert } 143c0b746e5SOllivier Robert 144c0b746e5SOllivier Robert void 145c0b746e5SOllivier Robert init_recvbuff(int nbufs) 146c0b746e5SOllivier Robert { 147c0b746e5SOllivier Robert 148c0b746e5SOllivier Robert /* 149c0b746e5SOllivier Robert * Init buffer free list and stat counters 150c0b746e5SOllivier Robert */ 151ea906c41SOllivier Robert free_recvbufs = total_recvbufs = 0; 152c0b746e5SOllivier Robert full_recvbufs = lowater_adds = 0; 153c0b746e5SOllivier Robert 154767173ceSCy Schubert limit_recvbufs = RECV_TOOMANY; 155767173ceSCy Schubert emerg_recvbufs = RECV_CLOCK; 156767173ceSCy Schubert 157ea906c41SOllivier Robert create_buffers(nbufs); 158ea906c41SOllivier Robert 159ea906c41SOllivier Robert # if defined(SYS_WINNT) 160ea906c41SOllivier Robert InitializeCriticalSection(&RecvLock); 161767173ceSCy Schubert InitializeCriticalSection(&FreeLock); 162c0b746e5SOllivier Robert # endif 163c0b746e5SOllivier Robert 1642b15cb3dSCy Schubert # ifdef DEBUG 1652b15cb3dSCy Schubert atexit(&uninit_recvbuff); 1662b15cb3dSCy Schubert # endif 167c0b746e5SOllivier Robert } 168c0b746e5SOllivier Robert 1692b15cb3dSCy Schubert 1702b15cb3dSCy Schubert #ifdef DEBUG 1712b15cb3dSCy Schubert static void 1722b15cb3dSCy Schubert uninit_recvbuff(void) 1732b15cb3dSCy Schubert { 1742b15cb3dSCy Schubert recvbuf_t *rbunlinked; 1752b15cb3dSCy Schubert 1762b15cb3dSCy Schubert for (;;) { 1772b15cb3dSCy Schubert UNLINK_FIFO(rbunlinked, full_recv_fifo, link); 1782b15cb3dSCy Schubert if (rbunlinked == NULL) 1792b15cb3dSCy Schubert break; 1802b15cb3dSCy Schubert free(rbunlinked); 1812b15cb3dSCy Schubert } 1822b15cb3dSCy Schubert 1832b15cb3dSCy Schubert for (;;) { 1842b15cb3dSCy Schubert UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); 1852b15cb3dSCy Schubert if (rbunlinked == NULL) 1862b15cb3dSCy Schubert break; 1872b15cb3dSCy Schubert free(rbunlinked); 1882b15cb3dSCy Schubert } 189767173ceSCy Schubert # if defined(SYS_WINNT) 190767173ceSCy Schubert DeleteCriticalSection(&FreeLock); 191767173ceSCy Schubert DeleteCriticalSection(&RecvLock); 192767173ceSCy Schubert # endif 1932b15cb3dSCy Schubert } 1942b15cb3dSCy Schubert #endif /* DEBUG */ 1952b15cb3dSCy Schubert 1962b15cb3dSCy Schubert 197c0b746e5SOllivier Robert /* 198c0b746e5SOllivier Robert * freerecvbuf - make a single recvbuf available for reuse 199c0b746e5SOllivier Robert */ 200c0b746e5SOllivier Robert void 201ea906c41SOllivier Robert freerecvbuf(recvbuf_t *rb) 202c0b746e5SOllivier Robert { 2034990d495SXin LI if (rb) { 204767173ceSCy Schubert if (--rb->used != 0) { 205ea906c41SOllivier Robert msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 206767173ceSCy Schubert rb->used = 0; 207767173ceSCy Schubert } 208767173ceSCy Schubert LOCK_F(); 2092b15cb3dSCy Schubert LINK_SLIST(free_recv_list, rb, link); 210767173ceSCy Schubert ++free_recvbufs; 211767173ceSCy Schubert UNLOCK_F(); 212c0b746e5SOllivier Robert } 2134990d495SXin LI } 214c0b746e5SOllivier Robert 215c0b746e5SOllivier Robert 216c0b746e5SOllivier Robert void 217ea906c41SOllivier Robert add_full_recv_buffer(recvbuf_t *rb) 218c0b746e5SOllivier Robert { 219ea906c41SOllivier Robert if (rb == NULL) { 220ea906c41SOllivier Robert msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); 221ea906c41SOllivier Robert return; 222c0b746e5SOllivier Robert } 223767173ceSCy Schubert LOCK_R(); 2242b15cb3dSCy Schubert LINK_FIFO(full_recv_fifo, rb, link); 225767173ceSCy Schubert ++full_recvbufs; 226767173ceSCy Schubert UNLOCK_R(); 227c0b746e5SOllivier Robert } 228c0b746e5SOllivier Robert 2292b15cb3dSCy Schubert 230ea906c41SOllivier Robert recvbuf_t * 231767173ceSCy Schubert get_free_recv_buffer( 232767173ceSCy Schubert int /*BOOL*/ urgent 233767173ceSCy Schubert ) 234c0b746e5SOllivier Robert { 235767173ceSCy Schubert recvbuf_t *buffer = NULL; 2362b15cb3dSCy Schubert 237767173ceSCy Schubert LOCK_F(); 238*a466cc55SCy Schubert if (free_recvbufs > (urgent ? 0 : emerg_recvbufs)) { 2392b15cb3dSCy Schubert UNLINK_HEAD_SLIST(buffer, free_recv_list, link); 240c0b746e5SOllivier Robert } 241767173ceSCy Schubert 242767173ceSCy Schubert if (buffer != NULL) { 243767173ceSCy Schubert if (free_recvbufs) 244767173ceSCy Schubert --free_recvbufs; 245767173ceSCy Schubert initialise_buffer(buffer); 246767173ceSCy Schubert ++buffer->used; 247767173ceSCy Schubert } else { 248767173ceSCy Schubert ++buffer_shortfall; 249767173ceSCy Schubert } 250767173ceSCy Schubert UNLOCK_F(); 2512b15cb3dSCy Schubert 2522b15cb3dSCy Schubert return buffer; 253c0b746e5SOllivier Robert } 254c0b746e5SOllivier Robert 2552b15cb3dSCy Schubert 256ea906c41SOllivier Robert #ifdef HAVE_IO_COMPLETION_PORT 257ea906c41SOllivier Robert recvbuf_t * 258767173ceSCy Schubert get_free_recv_buffer_alloc( 259767173ceSCy Schubert int /*BOOL*/ urgent 260767173ceSCy Schubert ) 261c0b746e5SOllivier Robert { 262767173ceSCy Schubert LOCK_F(); 263767173ceSCy Schubert if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0) 264ea906c41SOllivier Robert create_buffers(RECV_INC); 265767173ceSCy Schubert UNLOCK_F(); 266767173ceSCy Schubert return get_free_recv_buffer(urgent); 267c0b746e5SOllivier Robert } 268ea906c41SOllivier Robert #endif 269c0b746e5SOllivier Robert 2702b15cb3dSCy Schubert 271ea906c41SOllivier Robert recvbuf_t * 272c0b746e5SOllivier Robert get_full_recv_buffer(void) 273c0b746e5SOllivier Robert { 274ea906c41SOllivier Robert recvbuf_t * rbuf; 2752b15cb3dSCy Schubert 276ea906c41SOllivier Robert /* 277767173ceSCy Schubert * make sure there are free buffers when we wander off to do 278767173ceSCy Schubert * lengthy packet processing with any buffer we grab from the 279767173ceSCy Schubert * full list. 280ea906c41SOllivier Robert * 281767173ceSCy Schubert * fixes malloc() interrupted by SIGIO risk (Bug 889) 282ea906c41SOllivier Robert */ 283767173ceSCy Schubert LOCK_F(); 284767173ceSCy Schubert if (free_recvbufs <= emerg_recvbufs || buffer_shortfall > 0) 285ea906c41SOllivier Robert create_buffers(RECV_INC); 286767173ceSCy Schubert UNLOCK_F(); 287ea906c41SOllivier Robert 288ea906c41SOllivier Robert /* 289ea906c41SOllivier Robert * try to grab a full buffer 290ea906c41SOllivier Robert */ 291767173ceSCy Schubert LOCK_R(); 2922b15cb3dSCy Schubert UNLINK_FIFO(rbuf, full_recv_fifo, link); 293767173ceSCy Schubert if (rbuf != NULL && full_recvbufs) 294767173ceSCy Schubert --full_recvbufs; 295767173ceSCy Schubert UNLOCK_R(); 2962b15cb3dSCy Schubert 2972b15cb3dSCy Schubert return rbuf; 298ea906c41SOllivier Robert } 299ea906c41SOllivier Robert 3002b15cb3dSCy Schubert 3012b15cb3dSCy Schubert /* 3022b15cb3dSCy Schubert * purge_recv_buffers_for_fd() - purges any previously-received input 3032b15cb3dSCy Schubert * from a given file descriptor. 3042b15cb3dSCy Schubert */ 3052b15cb3dSCy Schubert void 3062b15cb3dSCy Schubert purge_recv_buffers_for_fd( 3074990d495SXin LI int fd 3082b15cb3dSCy Schubert ) 3092b15cb3dSCy Schubert { 3102b15cb3dSCy Schubert recvbuf_t *rbufp; 3112b15cb3dSCy Schubert recvbuf_t *next; 3122b15cb3dSCy Schubert recvbuf_t *punlinked; 313767173ceSCy Schubert recvbuf_t *freelist = NULL; 3142b15cb3dSCy Schubert 315767173ceSCy Schubert /* We want to hold only one lock at a time. So we do a scan on 316767173ceSCy Schubert * the full buffer queue, collecting items as we go, and when 317767173ceSCy Schubert * done we spool the the collected items to 'freerecvbuf()'. 318767173ceSCy Schubert */ 319767173ceSCy Schubert LOCK_R(); 3202b15cb3dSCy Schubert 3212b15cb3dSCy Schubert for (rbufp = HEAD_FIFO(full_recv_fifo); 3222b15cb3dSCy Schubert rbufp != NULL; 323767173ceSCy Schubert rbufp = next) 324767173ceSCy Schubert { 3252b15cb3dSCy Schubert next = rbufp->link; 3264990d495SXin LI # ifdef HAVE_IO_COMPLETION_PORT 3274990d495SXin LI if (rbufp->dstadr == NULL && rbufp->fd == fd) 3284990d495SXin LI # else 3294990d495SXin LI if (rbufp->fd == fd) 3304990d495SXin LI # endif 3314990d495SXin LI { 3322b15cb3dSCy Schubert UNLINK_MID_FIFO(punlinked, full_recv_fifo, 3332b15cb3dSCy Schubert rbufp, link, recvbuf_t); 3342b15cb3dSCy Schubert INSIST(punlinked == rbufp); 335767173ceSCy Schubert if (full_recvbufs) 336767173ceSCy Schubert --full_recvbufs; 337767173ceSCy Schubert rbufp->link = freelist; 338767173ceSCy Schubert freelist = rbufp; 3392b15cb3dSCy Schubert } 3402b15cb3dSCy Schubert } 3412b15cb3dSCy Schubert 342767173ceSCy Schubert UNLOCK_R(); 343767173ceSCy Schubert 344767173ceSCy Schubert while (freelist) { 345767173ceSCy Schubert next = freelist->link; 346767173ceSCy Schubert freerecvbuf(freelist); 347767173ceSCy Schubert freelist = next; 348767173ceSCy Schubert } 3492b15cb3dSCy Schubert } 3502b15cb3dSCy Schubert 3512b15cb3dSCy Schubert 352ea906c41SOllivier Robert /* 353ea906c41SOllivier Robert * Checks to see if there are buffers to process 354ea906c41SOllivier Robert */ 355ea906c41SOllivier Robert isc_boolean_t has_full_recv_buffer(void) 356ea906c41SOllivier Robert { 3572b15cb3dSCy Schubert if (HEAD_FIFO(full_recv_fifo) != NULL) 358ea906c41SOllivier Robert return (ISC_TRUE); 359ea906c41SOllivier Robert else 360ea906c41SOllivier Robert return (ISC_FALSE); 361c0b746e5SOllivier Robert } 3622b15cb3dSCy Schubert 3632b15cb3dSCy Schubert 3642b15cb3dSCy Schubert #ifdef NTP_DEBUG_LISTS_H 3652b15cb3dSCy Schubert void 3662b15cb3dSCy Schubert check_gen_fifo_consistency(void *fifo) 3672b15cb3dSCy Schubert { 3682b15cb3dSCy Schubert gen_fifo *pf; 3692b15cb3dSCy Schubert gen_node *pthis; 3702b15cb3dSCy Schubert gen_node **pptail; 3712b15cb3dSCy Schubert 3722b15cb3dSCy Schubert pf = fifo; 3732b15cb3dSCy Schubert REQUIRE((NULL == pf->phead && NULL == pf->pptail) || 3742b15cb3dSCy Schubert (NULL != pf->phead && NULL != pf->pptail)); 3752b15cb3dSCy Schubert 3762b15cb3dSCy Schubert pptail = &pf->phead; 3772b15cb3dSCy Schubert for (pthis = pf->phead; 3782b15cb3dSCy Schubert pthis != NULL; 3792b15cb3dSCy Schubert pthis = pthis->link) 3802b15cb3dSCy Schubert if (NULL != pthis->link) 3812b15cb3dSCy Schubert pptail = &pthis->link; 3822b15cb3dSCy Schubert 3832b15cb3dSCy Schubert REQUIRE(NULL == pf->pptail || pptail == pf->pptail); 3842b15cb3dSCy Schubert } 3852b15cb3dSCy Schubert #endif /* NTP_DEBUG_LISTS_H */ 386