source: trunk/third/xntp/xntpd/ntp_monitor.c @ 10832

Revision 10832, 8.4 KB checked in by brlewis, 27 years ago (diff)
This commit was generated by cvs2svn to compensate for changes in r10831, which included commits to RCS files with non-trunk default branches.
Line 
1/*
2 * ntp_monitor.c - monitor who is using the xntpd server
3 */
4#ifdef HAVE_CONFIG_H
5#include <config.h>
6#endif
7
8#include <stdio.h>
9#include <sys/types.h>
10#include <signal.h>
11#include <errno.h>
12# ifdef HAVE_SYS_IOCTL_H
13#  include <sys/ioctl.h>
14# endif
15# include <sys/time.h>
16
17#include "ntpd.h"
18#include "ntp_io.h"
19#include "ntp_if.h"
20#include "ntp_stdlib.h"
21
22/*
23 * I'm still not sure I like what I've done here.  It certainly consumes
24 * memory like it is going out of style, and also may not be as low
25 * overhead as I'd imagined.
26 *
27 * Anyway, we record statistics based on source address, mode and version
28 * (for now, anyway.  Check the code).  The receive procedure calls us with
29 * the incoming rbufp before it does anything else.
30 *
31 * Each entry is doubly linked into two lists, a hash table and a
32 * most-recently-used list.  When a packet arrives it is looked up
33 * in the hash table.  If found, the statistics are updated and the
34 * entry relinked at the head of the MRU list.  If not found, a new
35 * entry is allocated, initialized and linked into both the hash
36 * table and at the head of the MRU list.
37 *
38 * Memory is usually allocated by grabbing a big chunk of new memory
39 * and cutting it up into littler pieces.  The exception to this when we
40 * hit the memory limit.  Then we free memory by grabbing entries off
41 * the tail for the MRU list, unlinking from the hash table, and
42 * reinitializing.
43 *
44 * trimmed back memory consumption ... jdg 8/94
45 */
46
47/*
48 * Limits on the number of structures allocated.  This limit is picked
49 * with the illicit knowlege that we can only return somewhat less
50 * than 8K bytes in a mode 7 response packet, and that each structure
51 * will require about 20 bytes of space in the response.
52 *
53 * ... I don't believe the above is true anymore ... jdg
54 */
55#ifndef MAXMONMEM
56#define MAXMONMEM       600     /* we allocate up to 600 structures */
57#endif
58#ifndef MONMEMINC
59#define MONMEMINC       40      /* allocate them 40 at a time */
60#endif
61
62/*
63 * Hashing stuff
64 */
65#define MON_HASH_SIZE   128
66#define MON_HASH_MASK   (MON_HASH_SIZE-1)
67#define MON_HASH(addr)  ((int)(ntohl((addr)) & MON_HASH_MASK))
68
69/*
70 * Pointers to the hash table, the MRU list and the count table.  Memory
71 * for the hash and count tables is only allocated if monitoring is turned on.
72 */
73static  struct mon_data *mon_hash[MON_HASH_SIZE];  /* array of list ptrs */
74        struct mon_data mon_mru_list;
75        struct mon_data mon_fifo_list;
76/*
77 * List of free structures structures, and counters of free and total
78 * structures.  The free structures are linked with the hash_next field.
79 */
80static  struct mon_data *mon_free;      /* the free list or null if none */
81
82static  int mon_total_mem;              /* total number of structures allocated */
83static  int mon_mem_increments;         /* number of times we've called malloc() */
84
85/*
86 * Initialization state.  We may be monitoring, we may not.  If
87 * we aren't, we may not even have allocated any memory yet.
88 */
89        int mon_enabled;
90static  int mon_have_memory;
91
92/*
93 * Imported from the timer module
94 */
95extern u_long current_time;
96
97static  void    mon_getmoremem  P((void));
98static  void    remove_from_hash P((struct mon_data *));
99
100/*
101 * init_mon - initialize monitoring global data
102 */
103void
104init_mon()
105{
106        /*
107         * Don't do much of anything here.  We don't allocate memory
108         * until someone explicitly starts us.
109         */
110        mon_enabled = MON_OFF;
111        mon_have_memory = 0;
112
113        mon_total_mem = 0;
114        mon_mem_increments = 0;
115        mon_free = NULL;
116        memset((char *)&mon_hash[0], 0, sizeof mon_hash);
117        memset((char *)&mon_mru_list, 0, sizeof mon_mru_list);
118        memset((char *)&mon_fifo_list, 0, sizeof mon_fifo_list);
119}
120
121
122/*
123 * mon_start - start up the monitoring software
124 */
125void
126mon_start(mode)
127        int mode;
128{
129
130        if (mon_enabled != MON_OFF) {
131                mon_enabled |= mode;
132                return;
133        }
134        if (mode == MON_OFF)
135                return;         /* Ooops.. */
136       
137        if (!mon_have_memory) {
138                mon_total_mem = 0;
139                mon_mem_increments = 0;
140                mon_free = NULL;
141                mon_getmoremem();
142                mon_have_memory = 1;
143        }
144
145        mon_mru_list.mru_next = &mon_mru_list;
146        mon_mru_list.mru_prev = &mon_mru_list;
147
148        mon_fifo_list.fifo_next = &mon_fifo_list;
149        mon_fifo_list.fifo_prev = &mon_fifo_list;
150
151        mon_enabled = mode;
152}
153
154
155/*
156 * mon_stop - stop the monitoring software
157 */
158void
159mon_stop(mode)
160        int mode;
161{
162        register struct mon_data *md, *md_next;
163        register int i;
164
165        if (mon_enabled == MON_OFF)
166                return;
167        if ((mon_enabled & mode) == 0 || mode == MON_OFF)
168                return;
169
170        mon_enabled &= ~mode;
171        if (mon_enabled != MON_OFF)
172                return;
173       
174        /*
175         * Put everything back on the free list
176         */
177        for (i = 0; i < MON_HASH_SIZE; i++) {
178                md = mon_hash[i];               /* get next list */
179                mon_hash[i] = NULL;             /* zero the list head */
180                while (md != NULL) {
181                        md_next = md->hash_next;
182                        md->hash_next = mon_free;
183                        mon_free = md;
184                        md = md_next;
185                }
186        }
187
188        mon_mru_list.mru_next = &mon_mru_list;
189        mon_mru_list.mru_prev = &mon_mru_list;
190
191        mon_fifo_list.fifo_next = &mon_fifo_list;
192        mon_fifo_list.fifo_prev = &mon_fifo_list;
193}
194
195
196/*
197 * ntp_monitor - record stats about this packet
198 */
199void
200ntp_monitor(rbufp)
201        struct recvbuf *rbufp;
202{
203        register struct pkt *pkt;
204        register struct mon_data *md;
205        register u_long netnum;
206        register int hash;
207        register int mode;
208
209        if (mon_enabled == MON_OFF)
210                return;
211
212        pkt = &rbufp->recv_pkt;
213        netnum = NSRCADR(&rbufp->recv_srcadr);
214        hash = MON_HASH(netnum);
215        mode = PKT_MODE(pkt->li_vn_mode);
216
217        md = mon_hash[hash];
218        while (md != NULL) {
219                if (md->rmtadr == netnum &&
220                    /* ?? md->interface == rbufp->dstadr && ?? */
221                    md->mode == (u_char)mode) {
222                        md->lasttime = current_time;
223                        md->count++;
224                        md->version = PKT_VERSION(pkt->li_vn_mode);
225                        md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
226
227                        /*
228                         * Shuffle him to the head of the
229                         * mru list.  What a crock.
230                         */
231                        md->mru_next->mru_prev = md->mru_prev;
232                        md->mru_prev->mru_next = md->mru_next;
233                        md->mru_next = mon_mru_list.mru_next;
234                        md->mru_prev = &mon_mru_list;
235                        mon_mru_list.mru_next->mru_prev = md;
236                        mon_mru_list.mru_next = md;
237
238                        return;
239                }
240                md = md->hash_next;
241        }
242
243        /*
244         * If we got here, this is the first we've heard of this
245         * guy.  Get him some memory, either from the free list
246         * or from the tail of the MRU list.
247         */
248        if (mon_free == NULL && mon_total_mem >= MAXMONMEM) {
249                /*
250                 * Get it from MRU list
251                 */
252                md = mon_mru_list.mru_prev;
253                md->mru_prev->mru_next = &mon_mru_list;
254                mon_mru_list.mru_prev = md->mru_prev;
255
256                remove_from_hash(md);
257
258                /*
259                 * Get it from FIFO list
260                 */
261                md->fifo_prev->fifo_next = md->fifo_next;
262                md->fifo_next->fifo_prev = md->fifo_prev;
263               
264        } else {
265                if (mon_free == NULL)           /* if free list empty */
266                        mon_getmoremem();       /* then get more */
267                md = mon_free;
268                mon_free = md->hash_next;
269        }
270
271        /*
272         * Got one, initialize it
273         */
274        md->lasttime = md->firsttime = current_time;
275        md->lastdrop = 0;
276        md->count = 1;
277        md->rmtadr = netnum;
278        md->rmtport = NSRCPORT(&rbufp->recv_srcadr);
279        md->mode = (u_char) mode;
280        md->version = PKT_VERSION(pkt->li_vn_mode);
281        md->interface = rbufp->dstadr;
282        md->cast_flags = ((rbufp->dstadr->flags & INT_MULTICAST) &&
283            rbufp->fd == md->interface->fd) ? MDF_MCAST: rbufp->fd ==
284            md->interface->bfd ? MDF_BCAST : MDF_UCAST;
285
286        /*
287         * Drop him into front of the hash table.
288         * Also put him on top of the MRU list
289         * and at bottom of FIFO list
290         */
291
292        md->hash_next = mon_hash[hash];
293        mon_hash[hash] = md;
294
295        md->mru_next = mon_mru_list.mru_next;
296        md->mru_prev = &mon_mru_list;
297        mon_mru_list.mru_next->mru_prev = md;
298        mon_mru_list.mru_next = md;
299
300        md->fifo_prev = mon_fifo_list.fifo_prev;
301        md->fifo_next = &mon_fifo_list;
302        mon_fifo_list.fifo_prev->fifo_next = md;
303        mon_fifo_list.fifo_prev = md;
304}
305
306
307/*
308 * mon_getmoremem - get more memory and put it on the free list
309 */
310static void
311mon_getmoremem()
312{
313        register struct mon_data *md;
314        register int i;
315        struct mon_data *freedata;      /* 'old' free list (null) */
316
317        md = (struct mon_data *)emalloc(MONMEMINC * sizeof(struct mon_data));
318        freedata = mon_free;
319        mon_free = md;
320
321        for (i = 0; i < (MONMEMINC-1); i++) {
322                md->hash_next = (md + 1);
323                md++;
324        }
325
326        /*
327         * md now points at the last.  Link in the rest of the chain.
328         */
329        md->hash_next = freedata;
330
331        mon_total_mem += MONMEMINC;
332        mon_mem_increments++;
333}
334
335static void
336remove_from_hash(md)
337struct mon_data *md;
338{       register int hash;
339        register struct mon_data *md_prev;
340
341        hash = MON_HASH(md->rmtadr);
342        if (mon_hash[hash] == md) {
343                mon_hash[hash] = md->hash_next;
344        } else {
345                md_prev = mon_hash[hash];
346                while (md_prev->hash_next != md) {
347                        md_prev = md_prev->hash_next;
348                        if (md_prev == NULL) {
349                                /* logic error */
350                                return;
351                        }
352                }
353                md_prev->hash_next = md->hash_next;
354        }
355}
Note: See TracBrowser for help on using the repository browser.