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 142b15cb3dSCy Schubert 15c0b746e5SOllivier Robert /* 16c0b746e5SOllivier Robert * Memory allocation 17c0b746e5SOllivier Robert */ 182b15cb3dSCy Schubert static u_long volatile full_recvbufs; /* recvbufs on full_recv_fifo */ 192b15cb3dSCy Schubert static u_long volatile free_recvbufs; /* recvbufs on free_recv_list */ 20c0b746e5SOllivier Robert static u_long volatile total_recvbufs; /* total recvbufs currently in use */ 21c0b746e5SOllivier Robert static u_long volatile lowater_adds; /* number of times we have added memory */ 22ea906c41SOllivier Robert static u_long volatile buffer_shortfall;/* number of missed free receive buffers 23ea906c41SOllivier Robert between replenishments */ 24c0b746e5SOllivier Robert 252b15cb3dSCy Schubert static DECL_FIFO_ANCHOR(recvbuf_t) full_recv_fifo; 262b15cb3dSCy Schubert static recvbuf_t * free_recv_list; 27c0b746e5SOllivier Robert 28ea906c41SOllivier Robert #if defined(SYS_WINNT) 29ea906c41SOllivier Robert 30ea906c41SOllivier Robert /* 31ea906c41SOllivier Robert * For Windows we need to set up a lock to manipulate the 32ea906c41SOllivier Robert * recv buffers to prevent corruption. We keep it lock for as 33ea906c41SOllivier Robert * short a time as possible 34ea906c41SOllivier Robert */ 35ea906c41SOllivier Robert static CRITICAL_SECTION RecvLock; 36ea906c41SOllivier Robert # define LOCK() EnterCriticalSection(&RecvLock) 37ea906c41SOllivier Robert # define UNLOCK() LeaveCriticalSection(&RecvLock) 38c0b746e5SOllivier Robert #else 392b15cb3dSCy Schubert # define LOCK() do {} while (FALSE) 402b15cb3dSCy Schubert # define UNLOCK() do {} while (FALSE) 41c0b746e5SOllivier Robert #endif 42c0b746e5SOllivier Robert 432b15cb3dSCy Schubert #ifdef DEBUG 442b15cb3dSCy Schubert static void uninit_recvbuff(void); 452b15cb3dSCy Schubert #endif 462b15cb3dSCy Schubert 472b15cb3dSCy Schubert 48c0b746e5SOllivier Robert u_long 49c0b746e5SOllivier Robert free_recvbuffs (void) 50c0b746e5SOllivier Robert { 51c0b746e5SOllivier Robert return free_recvbufs; 52c0b746e5SOllivier Robert } 53c0b746e5SOllivier Robert 54c0b746e5SOllivier Robert u_long 55c0b746e5SOllivier Robert full_recvbuffs (void) 56c0b746e5SOllivier Robert { 57ea906c41SOllivier Robert return full_recvbufs; 58c0b746e5SOllivier Robert } 59c0b746e5SOllivier Robert 60c0b746e5SOllivier Robert u_long 61c0b746e5SOllivier Robert total_recvbuffs (void) 62c0b746e5SOllivier Robert { 63ea906c41SOllivier Robert return total_recvbufs; 64c0b746e5SOllivier Robert } 65c0b746e5SOllivier Robert 66c0b746e5SOllivier Robert u_long 67c0b746e5SOllivier Robert lowater_additions(void) 68c0b746e5SOllivier Robert { 69c0b746e5SOllivier Robert return lowater_adds; 70c0b746e5SOllivier Robert } 71c0b746e5SOllivier Robert 722b15cb3dSCy Schubert static inline void 73ea906c41SOllivier Robert initialise_buffer(recvbuf_t *buff) 74c0b746e5SOllivier Robert { 752b15cb3dSCy Schubert ZERO(*buff); 76c0b746e5SOllivier Robert } 77c0b746e5SOllivier Robert 78c0b746e5SOllivier Robert static void 79ea906c41SOllivier Robert create_buffers(int nbufs) 80c0b746e5SOllivier Robert { 81ea906c41SOllivier Robert register recvbuf_t *bufp; 82ea906c41SOllivier Robert int i, abuf; 83c0b746e5SOllivier Robert 84ea906c41SOllivier Robert abuf = nbufs + buffer_shortfall; 85ea906c41SOllivier Robert buffer_shortfall = 0; 86ea906c41SOllivier Robert 872b15cb3dSCy Schubert #ifndef DEBUG 882b15cb3dSCy Schubert bufp = emalloc_zero(abuf * sizeof(*bufp)); 892b15cb3dSCy Schubert #endif 90ea906c41SOllivier Robert 912b15cb3dSCy Schubert for (i = 0; i < abuf; i++) { 922b15cb3dSCy Schubert #ifdef DEBUG 932b15cb3dSCy Schubert /* 942b15cb3dSCy Schubert * Allocate each buffer individually so they can be 952b15cb3dSCy Schubert * free()d during ntpd shutdown on DEBUG builds to 962b15cb3dSCy Schubert * keep them out of heap leak reports. 972b15cb3dSCy Schubert */ 982b15cb3dSCy Schubert bufp = emalloc_zero(sizeof(*bufp)); 992b15cb3dSCy Schubert #endif 1002b15cb3dSCy Schubert LINK_SLIST(free_recv_list, bufp, link); 101ea906c41SOllivier Robert bufp++; 102ea906c41SOllivier Robert free_recvbufs++; 103ea906c41SOllivier Robert total_recvbufs++; 104ea906c41SOllivier Robert } 105c0b746e5SOllivier Robert lowater_adds++; 106c0b746e5SOllivier Robert } 107c0b746e5SOllivier Robert 108c0b746e5SOllivier Robert void 109c0b746e5SOllivier Robert init_recvbuff(int nbufs) 110c0b746e5SOllivier Robert { 111c0b746e5SOllivier Robert 112c0b746e5SOllivier Robert /* 113c0b746e5SOllivier Robert * Init buffer free list and stat counters 114c0b746e5SOllivier Robert */ 115ea906c41SOllivier Robert free_recvbufs = total_recvbufs = 0; 116c0b746e5SOllivier Robert full_recvbufs = lowater_adds = 0; 117c0b746e5SOllivier Robert 118ea906c41SOllivier Robert create_buffers(nbufs); 119ea906c41SOllivier Robert 120ea906c41SOllivier Robert #if defined(SYS_WINNT) 121ea906c41SOllivier Robert InitializeCriticalSection(&RecvLock); 122c0b746e5SOllivier Robert #endif 123c0b746e5SOllivier Robert 1242b15cb3dSCy Schubert #ifdef DEBUG 1252b15cb3dSCy Schubert atexit(&uninit_recvbuff); 1262b15cb3dSCy Schubert #endif 127c0b746e5SOllivier Robert } 128c0b746e5SOllivier Robert 1292b15cb3dSCy Schubert 1302b15cb3dSCy Schubert #ifdef DEBUG 1312b15cb3dSCy Schubert static void 1322b15cb3dSCy Schubert uninit_recvbuff(void) 1332b15cb3dSCy Schubert { 1342b15cb3dSCy Schubert recvbuf_t *rbunlinked; 1352b15cb3dSCy Schubert 1362b15cb3dSCy Schubert for (;;) { 1372b15cb3dSCy Schubert UNLINK_FIFO(rbunlinked, full_recv_fifo, link); 1382b15cb3dSCy Schubert if (rbunlinked == NULL) 1392b15cb3dSCy Schubert break; 1402b15cb3dSCy Schubert free(rbunlinked); 1412b15cb3dSCy Schubert } 1422b15cb3dSCy Schubert 1432b15cb3dSCy Schubert for (;;) { 1442b15cb3dSCy Schubert UNLINK_HEAD_SLIST(rbunlinked, free_recv_list, link); 1452b15cb3dSCy Schubert if (rbunlinked == NULL) 1462b15cb3dSCy Schubert break; 1472b15cb3dSCy Schubert free(rbunlinked); 1482b15cb3dSCy Schubert } 1492b15cb3dSCy Schubert } 1502b15cb3dSCy Schubert #endif /* DEBUG */ 1512b15cb3dSCy Schubert 1522b15cb3dSCy Schubert 153c0b746e5SOllivier Robert /* 154c0b746e5SOllivier Robert * freerecvbuf - make a single recvbuf available for reuse 155c0b746e5SOllivier Robert */ 156c0b746e5SOllivier Robert void 157ea906c41SOllivier Robert freerecvbuf(recvbuf_t *rb) 158c0b746e5SOllivier Robert { 159*4990d495SXin LI if (rb) { 160ea906c41SOllivier Robert LOCK(); 1612b15cb3dSCy Schubert rb->used--; 162ea906c41SOllivier Robert if (rb->used != 0) 163ea906c41SOllivier Robert msyslog(LOG_ERR, "******** freerecvbuff non-zero usage: %d *******", rb->used); 1642b15cb3dSCy Schubert LINK_SLIST(free_recv_list, rb, link); 165c0b746e5SOllivier Robert free_recvbufs++; 166ea906c41SOllivier Robert UNLOCK(); 167c0b746e5SOllivier Robert } 168*4990d495SXin LI } 169c0b746e5SOllivier Robert 170c0b746e5SOllivier Robert 171c0b746e5SOllivier Robert void 172ea906c41SOllivier Robert add_full_recv_buffer(recvbuf_t *rb) 173c0b746e5SOllivier Robert { 174ea906c41SOllivier Robert if (rb == NULL) { 175ea906c41SOllivier Robert msyslog(LOG_ERR, "add_full_recv_buffer received NULL buffer"); 176ea906c41SOllivier Robert return; 177c0b746e5SOllivier Robert } 178ea906c41SOllivier Robert LOCK(); 1792b15cb3dSCy Schubert LINK_FIFO(full_recv_fifo, rb, link); 180c0b746e5SOllivier Robert full_recvbufs++; 181ea906c41SOllivier Robert UNLOCK(); 182c0b746e5SOllivier Robert } 183c0b746e5SOllivier Robert 1842b15cb3dSCy Schubert 185ea906c41SOllivier Robert recvbuf_t * 186c0b746e5SOllivier Robert get_free_recv_buffer(void) 187c0b746e5SOllivier Robert { 1882b15cb3dSCy Schubert recvbuf_t *buffer; 1892b15cb3dSCy Schubert 190ea906c41SOllivier Robert LOCK(); 1912b15cb3dSCy Schubert UNLINK_HEAD_SLIST(buffer, free_recv_list, link); 1922b15cb3dSCy Schubert if (buffer != NULL) { 193ea906c41SOllivier Robert free_recvbufs--; 194ea906c41SOllivier Robert initialise_buffer(buffer); 1952b15cb3dSCy Schubert buffer->used++; 1962b15cb3dSCy Schubert } else { 197ea906c41SOllivier Robert buffer_shortfall++; 198c0b746e5SOllivier Robert } 199ea906c41SOllivier Robert UNLOCK(); 2002b15cb3dSCy Schubert 2012b15cb3dSCy Schubert return buffer; 202c0b746e5SOllivier Robert } 203c0b746e5SOllivier Robert 2042b15cb3dSCy Schubert 205ea906c41SOllivier Robert #ifdef HAVE_IO_COMPLETION_PORT 206ea906c41SOllivier Robert recvbuf_t * 207ea906c41SOllivier Robert get_free_recv_buffer_alloc(void) 208c0b746e5SOllivier Robert { 2092b15cb3dSCy Schubert recvbuf_t *buffer; 2102b15cb3dSCy Schubert 2112b15cb3dSCy Schubert buffer = get_free_recv_buffer(); 2122b15cb3dSCy Schubert if (NULL == buffer) { 213ea906c41SOllivier Robert create_buffers(RECV_INC); 214ea906c41SOllivier Robert buffer = get_free_recv_buffer(); 215c0b746e5SOllivier Robert } 2169034852cSGleb Smirnoff ENSURE(buffer != NULL); 217ea906c41SOllivier Robert return (buffer); 218c0b746e5SOllivier Robert } 219ea906c41SOllivier Robert #endif 220c0b746e5SOllivier Robert 2212b15cb3dSCy Schubert 222ea906c41SOllivier Robert recvbuf_t * 223c0b746e5SOllivier Robert get_full_recv_buffer(void) 224c0b746e5SOllivier Robert { 225ea906c41SOllivier Robert recvbuf_t * rbuf; 2262b15cb3dSCy Schubert 227ea906c41SOllivier Robert LOCK(); 228ea906c41SOllivier Robert 229ea906c41SOllivier Robert #ifdef HAVE_SIGNALED_IO 230ea906c41SOllivier Robert /* 231ea906c41SOllivier Robert * make sure there are free buffers when we 2322b15cb3dSCy Schubert * wander off to do lengthy packet processing with 233ea906c41SOllivier Robert * any buffer we grab from the full list. 234ea906c41SOllivier Robert * 235ea906c41SOllivier Robert * fixes malloc() interrupted by SIGIO risk 236ea906c41SOllivier Robert * (Bug 889) 237ea906c41SOllivier Robert */ 2382b15cb3dSCy Schubert if (NULL == free_recv_list || buffer_shortfall > 0) { 239ea906c41SOllivier Robert /* 240ea906c41SOllivier Robert * try to get us some more buffers 241ea906c41SOllivier Robert */ 242ea906c41SOllivier Robert create_buffers(RECV_INC); 243c0b746e5SOllivier Robert } 244ea906c41SOllivier Robert #endif 245ea906c41SOllivier Robert 246ea906c41SOllivier Robert /* 247ea906c41SOllivier Robert * try to grab a full buffer 248ea906c41SOllivier Robert */ 2492b15cb3dSCy Schubert UNLINK_FIFO(rbuf, full_recv_fifo, link); 250ea906c41SOllivier Robert if (rbuf != NULL) 2512b15cb3dSCy Schubert full_recvbufs--; 252ea906c41SOllivier Robert UNLOCK(); 2532b15cb3dSCy Schubert 2542b15cb3dSCy Schubert return rbuf; 255ea906c41SOllivier Robert } 256ea906c41SOllivier Robert 2572b15cb3dSCy Schubert 2582b15cb3dSCy Schubert /* 2592b15cb3dSCy Schubert * purge_recv_buffers_for_fd() - purges any previously-received input 2602b15cb3dSCy Schubert * from a given file descriptor. 2612b15cb3dSCy Schubert */ 2622b15cb3dSCy Schubert void 2632b15cb3dSCy Schubert purge_recv_buffers_for_fd( 264*4990d495SXin LI int fd 2652b15cb3dSCy Schubert ) 2662b15cb3dSCy Schubert { 2672b15cb3dSCy Schubert recvbuf_t *rbufp; 2682b15cb3dSCy Schubert recvbuf_t *next; 2692b15cb3dSCy Schubert recvbuf_t *punlinked; 2702b15cb3dSCy Schubert 2712b15cb3dSCy Schubert LOCK(); 2722b15cb3dSCy Schubert 2732b15cb3dSCy Schubert for (rbufp = HEAD_FIFO(full_recv_fifo); 2742b15cb3dSCy Schubert rbufp != NULL; 2752b15cb3dSCy Schubert rbufp = next) { 2762b15cb3dSCy Schubert next = rbufp->link; 277*4990d495SXin LI # ifdef HAVE_IO_COMPLETION_PORT 278*4990d495SXin LI if (rbufp->dstadr == NULL && rbufp->fd == fd) 279*4990d495SXin LI # else 280*4990d495SXin LI if (rbufp->fd == fd) 281*4990d495SXin LI # endif 282*4990d495SXin LI { 2832b15cb3dSCy Schubert UNLINK_MID_FIFO(punlinked, full_recv_fifo, 2842b15cb3dSCy Schubert rbufp, link, recvbuf_t); 2852b15cb3dSCy Schubert INSIST(punlinked == rbufp); 2862b15cb3dSCy Schubert full_recvbufs--; 2872b15cb3dSCy Schubert freerecvbuf(rbufp); 2882b15cb3dSCy Schubert } 2892b15cb3dSCy Schubert } 2902b15cb3dSCy Schubert 2912b15cb3dSCy Schubert UNLOCK(); 2922b15cb3dSCy Schubert } 2932b15cb3dSCy Schubert 2942b15cb3dSCy Schubert 295ea906c41SOllivier Robert /* 296ea906c41SOllivier Robert * Checks to see if there are buffers to process 297ea906c41SOllivier Robert */ 298ea906c41SOllivier Robert isc_boolean_t has_full_recv_buffer(void) 299ea906c41SOllivier Robert { 3002b15cb3dSCy Schubert if (HEAD_FIFO(full_recv_fifo) != NULL) 301ea906c41SOllivier Robert return (ISC_TRUE); 302ea906c41SOllivier Robert else 303ea906c41SOllivier Robert return (ISC_FALSE); 304c0b746e5SOllivier Robert } 3052b15cb3dSCy Schubert 3062b15cb3dSCy Schubert 3072b15cb3dSCy Schubert #ifdef NTP_DEBUG_LISTS_H 3082b15cb3dSCy Schubert void 3092b15cb3dSCy Schubert check_gen_fifo_consistency(void *fifo) 3102b15cb3dSCy Schubert { 3112b15cb3dSCy Schubert gen_fifo *pf; 3122b15cb3dSCy Schubert gen_node *pthis; 3132b15cb3dSCy Schubert gen_node **pptail; 3142b15cb3dSCy Schubert 3152b15cb3dSCy Schubert pf = fifo; 3162b15cb3dSCy Schubert REQUIRE((NULL == pf->phead && NULL == pf->pptail) || 3172b15cb3dSCy Schubert (NULL != pf->phead && NULL != pf->pptail)); 3182b15cb3dSCy Schubert 3192b15cb3dSCy Schubert pptail = &pf->phead; 3202b15cb3dSCy Schubert for (pthis = pf->phead; 3212b15cb3dSCy Schubert pthis != NULL; 3222b15cb3dSCy Schubert pthis = pthis->link) 3232b15cb3dSCy Schubert if (NULL != pthis->link) 3242b15cb3dSCy Schubert pptail = &pthis->link; 3252b15cb3dSCy Schubert 3262b15cb3dSCy Schubert REQUIRE(NULL == pf->pptail || pptail == pf->pptail); 3272b15cb3dSCy Schubert } 3282b15cb3dSCy Schubert #endif /* NTP_DEBUG_LISTS_H */ 329