Be explicit that per-host pages are directories.
[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 "darkstat.h"
11 #include "conv.h"
12 #include "err.h"
13 #include "ncache.h"
14 #include "tree.h"
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: */