Remove includes of darkstat.h, add cdefs.h where needed.
[darkstat.git] / ncache.c
1 /* darkstat 3
2  * copyright (c) 2001-2006 Emil Mikulic.
3  *
4  * ncache.c: cache of protocol and service names.
5  *
6  * You may use, modify and redistribute this file under the terms of the
7  * GNU General Public License version 2. (see COPYING.GPL)
8  */
9
10 #include "conv.h"
11 #include "err.h"
12 #include "ncache.h"
13 #include "tree.h"
14
15 #include <netinet/in.h> /* ntohs */
16 #include <netdb.h>
17 #include <stdlib.h>
18 #include <string.h>
19
20 struct name_rec {
21    RB_ENTRY(name_rec) ptree;
22    int num;
23    char *name;
24 };
25
26 static int
27 rec_cmp(struct name_rec *a, struct name_rec *b)
28 {
29    if (a->num < b->num) return (-1); else
30    if (a->num > b->num) return (+1); else
31    return (0);
32 }
33
34 RB_HEAD(nc_tree, name_rec);
35 RB_GENERATE(nc_tree, name_rec, ptree, rec_cmp)
36
37 static struct nc_tree
38    t_proto   = RB_INITIALIZER(&name_rec),
39    t_servtcp = RB_INITIALIZER(&name_rec),
40    t_servudp = RB_INITIALIZER(&name_rec);
41
42 static void
43 add_rec(struct nc_tree *tree, const int num, const char *name)
44 {
45    struct name_rec *e, *r = xmalloc(sizeof(*r));
46
47    r->num = num;
48    e = RB_INSERT(nc_tree, tree, r);
49
50    if (e != NULL) {
51       size_t newlen;
52
53       /* record exists: append service name, free record */
54       newlen = strlen(e->name) + strlen(name) + 2;
55       e->name = xrealloc(e->name, newlen);
56       strlcat(e->name, " ", newlen);
57       strlcat(e->name, name, newlen);
58       free(r);
59    }
60    else {
61       /* record added: fill out name field */
62       r->name = xstrdup(name);
63    }
64 }
65
66 void
67 ncache_init(void)
68 {
69    struct protoent *pe;
70    struct servent *se;
71    int count, ctcp, cudp;
72
73    count = 0;
74    setprotoent(0);
75    while ((pe = getprotoent()) != NULL) {
76       add_rec(&t_proto, pe->p_proto, pe->p_name);
77       count++;
78    }
79    endprotoent();
80    verbosef("loaded %d protos", count);
81
82    count = ctcp = cudp = 0;
83    setservent(0);
84    while ((se = getservent()) != NULL) {
85       if (strcmp(se->s_proto, "tcp") == 0) {
86          add_rec(&t_servtcp, ntohs(se->s_port), se->s_name);
87          ctcp++;
88       }
89       else if (strcmp(se->s_proto, "udp") == 0) {
90          add_rec(&t_servudp, ntohs(se->s_port), se->s_name);
91          cudp++;
92       }
93       count++;
94    }
95    endservent();
96    verbosef("loaded %d tcp and %d udp servs, from total %d",
97       ctcp, cudp, count);
98 }
99
100 static void
101 tree_free(struct nc_tree *tree)
102 {
103    struct name_rec *curr, *next;
104
105    for (curr = RB_MIN(nc_tree, tree); curr != NULL; curr = next) {
106       next = RB_NEXT(nc_tree, tree, curr);
107       RB_REMOVE(nc_tree, tree, curr);
108       free(curr->name);
109       free(curr);
110    }
111 }
112
113 void
114 ncache_free(void)
115 {
116    tree_free(&t_proto);
117    tree_free(&t_servtcp);
118    tree_free(&t_servudp);
119 }
120
121 #define FIND(tree,n) { \
122    struct name_rec r, *f; \
123    r.num = n; \
124    f = RB_FIND(nc_tree, &tree, &r); \
125    if (f == NULL) \
126       return (""); \
127    else \
128       return (f->name); \
129 }
130
131 const char *
132 getproto(const int proto)
133 FIND(t_proto, proto)
134
135 const char *
136 getservtcp(const int port)
137 FIND(t_servtcp, port)
138
139 const char *
140 getservudp(const int port)
141 FIND(t_servudp, port)
142
143 /* vim:set ts=3 sw=3 tw=78 expandtab: */