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