Homepage is moving to a sillier domain.
[darkstat] / 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: */