1 #ifdef HAVE_CONFIG_H 2 # include <config.h> 3 #endif 4 5 #include <stdio.h> 6 #include "ntp_machine.h" 7 #include "ntp_fp.h" 8 #include "ntp_stdlib.h" 9 #include "ntp_syslog.h" 10 #include "ntp_io.h" 11 #include "recvbuff.h" 12 #include "iosignal.h" 13 14 /* 15 * Memory allocation 16 */ 17 static u_long volatile full_recvbufs; /* number of recvbufs on fulllist */ 18 static u_long volatile free_recvbufs; /* number of recvbufs on freelist */ 19 static u_long volatile total_recvbufs; /* total recvbufs currently in use */ 20 static u_long volatile lowater_adds; /* number of times we have added memory */ 21 22 static struct recvbuf *volatile freelist; /* free buffers */ 23 static struct recvbuf *volatile fulllist; /* lifo buffers with data */ 24 static struct recvbuf *volatile beginlist; /* fifo buffers with data */ 25 26 #if defined(HAVE_IO_COMPLETION_PORT) 27 static HANDLE fulldatabufferevent; 28 static CRITICAL_SECTION RecvCritSection; 29 # define RECV_BLOCK_IO() EnterCriticalSection(&RecvCritSection) 30 # define RECV_UNBLOCK_IO() LeaveCriticalSection(&RecvCritSection) 31 #else 32 # define RECV_BLOCK_IO() 33 # define RECV_UNBLOCK_IO() 34 #endif 35 36 u_long 37 free_recvbuffs (void) 38 { 39 return free_recvbufs; 40 } 41 42 u_long 43 full_recvbuffs (void) 44 { 45 return free_recvbufs; 46 } 47 48 u_long 49 total_recvbuffs (void) 50 { 51 return free_recvbufs; 52 } 53 54 u_long 55 lowater_additions(void) 56 { 57 return lowater_adds; 58 } 59 60 static void 61 initialise_buffer(struct recvbuf *buff) 62 { 63 memset((char *) buff, 0, sizeof(struct recvbuf)); 64 65 #if defined HAVE_IO_COMPLETION_PORT 66 buff->iocompletioninfo.overlapped.hEvent = CreateEvent(NULL, FALSE,FALSE, NULL); 67 buff->wsabuff.len = RX_BUFF_SIZE; 68 buff->wsabuff.buf = (char *) buff->recv_buffer; 69 #endif 70 } 71 72 static void 73 create_buffers(void) 74 { 75 register struct recvbuf *buf; 76 int i; 77 buf = (struct recvbuf *) 78 emalloc(RECV_INC*sizeof(struct recvbuf)); 79 for (i = 0; i < RECV_INC; i++) 80 { 81 initialise_buffer(buf); 82 buf->next = (struct recvbuf *) freelist; 83 freelist = buf; 84 buf++; 85 } 86 87 free_recvbufs += RECV_INC; 88 total_recvbufs += RECV_INC; 89 lowater_adds++; 90 } 91 92 void 93 init_recvbuff(int nbufs) 94 { 95 register struct recvbuf *buf; 96 int i; 97 98 /* 99 * Init buffer free list and stat counters 100 */ 101 freelist = 0; 102 103 buf = (struct recvbuf *) 104 emalloc(nbufs*sizeof(struct recvbuf)); 105 for (i = 0; i < nbufs; i++) 106 { 107 initialise_buffer(buf); 108 buf->next = (struct recvbuf *) freelist; 109 freelist = buf; 110 buf++; 111 } 112 113 fulllist = 0; 114 free_recvbufs = total_recvbufs = nbufs; 115 full_recvbufs = lowater_adds = 0; 116 117 #if defined(HAVE_IO_COMPLETION_PORT) 118 InitializeCriticalSection(&RecvCritSection); 119 fulldatabufferevent = CreateEvent(NULL, FALSE,FALSE, NULL); 120 #endif 121 122 } 123 124 #if defined(HAVE_IO_COMPLETION_PORT) 125 126 /* Return the new full buffer event handle . This handle is 127 * signalled when a recv buffer is placed in the full list. 128 */ 129 HANDLE 130 get_recv_buff_event() 131 { 132 return fulldatabufferevent; 133 } 134 #endif 135 136 /* 137 * getrecvbufs - get receive buffers which have data in them 138 * 139 * 140 */ 141 142 struct recvbuf * 143 getrecvbufs(void) 144 { 145 struct recvbuf *rb = NULL; /* nothing has arrived */; 146 147 RECV_BLOCK_IO(); 148 if (full_recvbufs == 0) 149 { 150 #ifdef DEBUG 151 if (debug > 4) 152 printf("getrecvbufs called, no action here\n"); 153 #endif 154 } 155 else { 156 157 /* 158 * Get the fulllist chain and mark it empty 159 */ 160 #ifdef DEBUG 161 if (debug > 4) 162 printf("getrecvbufs returning %ld buffers\n", full_recvbufs); 163 #endif 164 rb = beginlist; 165 fulllist = 0; 166 full_recvbufs = 0; 167 168 /* 169 * Check to see if we're below the low water mark. 170 */ 171 if (free_recvbufs <= RECV_LOWAT) 172 { 173 if (total_recvbufs >= RECV_TOOMANY) 174 msyslog(LOG_ERR, "too many recvbufs allocated (%ld)", 175 total_recvbufs); 176 else 177 { 178 create_buffers(); 179 } 180 } 181 } 182 RECV_UNBLOCK_IO(); 183 184 /* 185 * Return the chain 186 */ 187 return rb; 188 } 189 190 /* 191 * freerecvbuf - make a single recvbuf available for reuse 192 */ 193 void 194 freerecvbuf( 195 struct recvbuf *rb 196 ) 197 { 198 RECV_BLOCK_IO(); 199 BLOCKIO(); 200 rb->next = (struct recvbuf *) freelist; 201 freelist = rb; 202 free_recvbufs++; 203 UNBLOCKIO(); 204 RECV_UNBLOCK_IO(); 205 } 206 207 208 void 209 add_full_recv_buffer( 210 struct recvbuf *rb 211 ) 212 { 213 RECV_BLOCK_IO(); 214 if (full_recvbufs == 0) 215 { 216 beginlist = rb; 217 rb->next = 0; 218 } 219 else 220 { 221 rb->next = fulllist->next; 222 fulllist->next = rb; 223 } 224 fulllist = rb; 225 full_recvbufs++; 226 227 #if defined(HAVE_IO_COMPLETION_PORT) 228 if (!SetEvent(fulldatabufferevent)) { 229 msyslog(LOG_ERR, "Can't set receive buffer event"); 230 } 231 #endif 232 RECV_UNBLOCK_IO(); 233 } 234 235 struct recvbuf * 236 get_free_recv_buffer(void) 237 { 238 struct recvbuf * buffer = NULL; 239 RECV_BLOCK_IO(); 240 if (free_recvbufs <= RECV_LOWAT) 241 { 242 if (total_recvbufs >= RECV_TOOMANY) { 243 msyslog(LOG_ERR, "too many recvbufs allocated (%ld)", 244 total_recvbufs); 245 } 246 else 247 { 248 create_buffers(); 249 } 250 } 251 252 if (free_recvbufs > 0) 253 { 254 buffer = freelist; 255 freelist = buffer->next; 256 buffer->next = NULL; 257 --free_recvbufs; 258 } 259 260 RECV_UNBLOCK_IO(); 261 return buffer; 262 } 263 264 struct recvbuf * 265 get_full_recv_buffer(void) 266 { 267 struct recvbuf * buffer = NULL; 268 RECV_BLOCK_IO(); 269 if (full_recvbufs > 0) { 270 --full_recvbufs; 271 buffer = beginlist; 272 beginlist = buffer->next; 273 buffer->next = NULL; 274 } 275 RECV_UNBLOCK_IO(); 276 return buffer; 277 } 278