64396bf1e7815b0edf915e67a6fde4b5e46a749e
[trust_router.git] / trp / trp_rtable.c
1 #include <glib.h>
2 #include <talloc.h>
3
4 #include <trust_router/tr_name.h>
5 #include <trp_internal.h>
6 #include <trp_rtable.h>
7 #include <tr_debug.h>
8
9 /* Note: be careful mixing talloc with glib. */
10
11 static int trp_rentry_destructor(void *obj)
12 {
13   TRP_RENTRY *entry=talloc_get_type_abort(obj, TRP_RENTRY);
14   if (entry->apc!=NULL)
15     tr_free_name(entry->apc);
16   if (entry->realm!=NULL)
17     tr_free_name(entry->realm);
18   if (entry->trust_router!=NULL)
19     tr_free_name(entry->trust_router);
20   if (entry->peer!=NULL)
21     tr_free_name(entry->peer);
22   if (entry->next_hop!=NULL)
23     tr_free_name(entry->next_hop);
24   return 0;
25 }
26
27 TRP_RENTRY *trp_rentry_new(TALLOC_CTX *mem_ctx)
28 {
29   TRP_RENTRY *entry=talloc(mem_ctx, TRP_RENTRY);
30   if (entry!=NULL) {
31     entry->apc=NULL;
32     entry->realm=NULL;
33     entry->trust_router=NULL;
34     entry->peer=NULL;
35     entry->next_hop=NULL;
36     entry->selected=0;
37     entry->expiry=talloc(entry, struct timespec);
38     if (entry->expiry==NULL) {
39       talloc_free(entry);
40       return NULL;
41     }
42     talloc_set_destructor((void *)entry, trp_rentry_destructor);
43   }
44   tr_debug("trp_rentry_new: %p", entry);
45   return entry;
46 }
47
48 void trp_rentry_free(TRP_RENTRY *entry)
49 {
50   if (entry!=NULL)
51     talloc_free(entry);
52 }
53
54 void trp_rentry_set_apc(TRP_RENTRY *entry, TR_NAME *apc)
55 {
56   entry->apc=apc;
57 }
58
59 TR_NAME *trp_rentry_get_apc(TRP_RENTRY *entry)
60 {
61   return entry->apc;
62 }
63
64 void trp_rentry_set_realm(TRP_RENTRY *entry, TR_NAME *realm)
65 {
66   entry->realm=realm;
67 }
68
69 TR_NAME *trp_rentry_get_realm(TRP_RENTRY *entry)
70 {
71   return entry->realm;
72 }
73
74 void trp_rentry_set_trust_router(TRP_RENTRY *entry, TR_NAME *tr)
75 {
76   entry->trust_router=tr;
77 }
78
79 TR_NAME *trp_rentry_get_trust_router(TRP_RENTRY *entry)
80 {
81   return entry->trust_router;
82 }
83
84 void trp_rentry_set_peer(TRP_RENTRY *entry, TR_NAME *peer)
85 {
86   entry->peer=peer;
87 }
88
89 TR_NAME *trp_rentry_get_peer(TRP_RENTRY *entry)
90 {
91   return entry->peer;
92 }
93
94 void trp_rentry_set_metric(TRP_RENTRY *entry, unsigned int metric)
95 {
96   entry->metric=metric;
97 }
98
99 unsigned int trp_rentry_get_metric(TRP_RENTRY *entry)
100 {
101   return entry->metric;
102 }
103
104 void trp_rentry_set_next_hop(TRP_RENTRY *entry, TR_NAME *next_hop)
105 {
106   entry->next_hop=next_hop;
107 }
108
109 TR_NAME *trp_rentry_get_next_hop(TRP_RENTRY *entry)
110 {
111   return entry->next_hop;
112 }
113
114 void trp_rentry_set_selected(TRP_RENTRY *entry, int sel)
115 {
116   entry->selected=sel;
117 }
118
119 int trp_rentry_get_selected(TRP_RENTRY *entry)
120 {
121   return entry->selected;
122 }
123
124 /* copies incoming value, does not assume responsibility for freeing */
125 void trp_rentry_set_expiry(TRP_RENTRY *entry, struct timespec *exp)
126 {
127   entry->expiry->tv_sec=exp->tv_sec;
128   entry->expiry->tv_nsec=exp->tv_nsec;
129 }
130
131 struct timespec *trp_rentry_get_expiry(TRP_RENTRY *entry)
132 {
133   return entry->expiry;
134 }
135
136
137 /* result must be freed with g_free */
138 static gchar *tr_name_to_g_str(const TR_NAME *n)
139 {
140   gchar *s=g_strndup(n->buf, n->len);
141   return s;
142 }
143
144 /* hash function for TR_NAME keys */
145 static guint trp_tr_name_hash(gconstpointer key)
146 {
147   const TR_NAME *name=(TR_NAME *)key;
148   gchar *s=tr_name_to_g_str(name);
149   guint hash=g_str_hash(s);
150   g_free(s);
151   return hash;
152 }
153
154 /* hash equality function for TR_NAME keys */
155 static gboolean trp_tr_name_equal(gconstpointer key1, gconstpointer key2)
156 {
157   const TR_NAME *n1=(TR_NAME *)key1;
158   const TR_NAME *n2=(TR_NAME *)key2;
159   gchar *s1=tr_name_to_g_str(n1);
160   gchar *s2=tr_name_to_g_str(n2);
161   gboolean equal=g_str_equal(s1, s2);
162   g_free(s1);
163   g_free(s2);
164   return equal;
165 }
166
167 /* free a value to the top level rtable (a hash of all entries in the apc) */
168 static void trp_rtable_destroy_table(gpointer data)
169 {
170   g_hash_table_destroy(data);
171 }
172
173 static void trp_rtable_destroy_rentry(gpointer data)
174 {
175   trp_rentry_free(data);
176 }
177
178 TRP_RTABLE *trp_rtable_new(void)
179 {
180   GHashTable *new=g_hash_table_new_full(trp_tr_name_hash,
181                                         trp_tr_name_equal,
182                                         NULL, /* no need to free the key, it is part of the TRP_RENTRY */
183                                         trp_rtable_destroy_table);
184   tr_debug("trp_rtable_new: %p", new);
185   return new;
186 }
187
188 void trp_rtable_free(TRP_RTABLE *rtbl)
189 {
190   g_hash_table_destroy(rtbl);
191 }
192
193 static GHashTable *trp_rtbl_get_or_add_table(GHashTable *tbl, TR_NAME *key, GDestroyNotify destroy)
194 {
195   GHashTable *val_tbl=NULL;
196
197   val_tbl=g_hash_table_lookup(tbl, key);
198   if (val_tbl==NULL) {
199     val_tbl=g_hash_table_new_full(trp_tr_name_hash,
200                                   trp_tr_name_equal,
201                                   NULL, /* no need to free the key */
202                                   destroy);
203     tr_debug("tr_rtbl_get_or_add_table: %p", val_tbl, trp_rtable_destroy_table);
204     g_hash_table_insert(tbl, key, val_tbl);
205   }
206   return val_tbl;
207 }
208
209 void trp_rtable_add(TRP_RTABLE *rtbl, TRP_RENTRY *entry)
210 {
211   GHashTable *apc_tbl=NULL;
212   GHashTable *realm_tbl=NULL;
213
214   apc_tbl=trp_rtbl_get_or_add_table(rtbl, entry->apc, trp_rtable_destroy_table);
215   realm_tbl=trp_rtbl_get_or_add_table(apc_tbl, entry->realm, trp_rtable_destroy_rentry);
216   g_hash_table_insert(realm_tbl, entry->peer, entry); /* destroys and replaces a duplicate */
217 }
218
219 void trp_rtable_remove(TRP_RTABLE *rtbl, TRP_RENTRY *entry)
220 {
221   GHashTable *apc_tbl=NULL;
222   GHashTable *realm_tbl=NULL;
223
224   apc_tbl=g_hash_table_lookup(rtbl, entry->apc);
225   if (apc_tbl==NULL)
226     return;
227   realm_tbl=g_hash_table_lookup(apc_tbl, entry->realm);
228   if (realm_tbl==NULL)
229     return;
230   g_hash_table_remove(realm_tbl, entry->peer);
231 }
232
233 /* Get all entries in an apc. Returned as a talloc'ed array in the NULL
234  * context. Caller should free these. */
235 size_t trp_rtable_get_apc(TRP_RTABLE *rtbl, TR_NAME *apc, TRP_RENTRY **ret)
236 {
237   GHashTable *apc_tbl=NULL;
238   size_t len=0; /* length of return array */
239   size_t ii=0;
240   GList *realms=NULL;
241   GList *realm_entries=NULL;
242   GList *p1=NULL, *p2=NULL;
243
244   apc_tbl=g_hash_table_lookup(rtbl, apc);
245   if (apc_tbl==NULL)
246     return 0;
247
248   realms=g_hash_table_get_values(apc_tbl);
249   /* make two passes: first count the entries, then allocate and populate the output array */
250   for (p1=realms; p1!=NULL; p1=g_list_next(p1))
251     len+=g_hash_table_size(p1->data);
252   if (len==0) {
253     g_list_free(realms);
254     return 0;
255   }
256
257   *ret=talloc_array(NULL, TRP_RENTRY, len);
258   if (*ret==NULL) {
259     tr_crit("trp_rtable_get_apc: could not allocate return array.");
260     g_list_free(realms);
261     return 0;
262   }
263
264   ii=0;
265   for (p1=realms; p1!=NULL; p1=g_list_next(p1)) {
266     realm_entries=g_hash_table_get_values(p1->data);
267     for (p2=realm_entries; p2!=NULL; p2=g_list_next(p2)) {
268       memcpy(*ret+ii, p2->data, sizeof(TRP_RENTRY));
269       ii++;
270     }
271     g_list_free(realm_entries);
272   }
273
274   g_list_free(realms);
275   return len;
276 }
277
278 /* Get all entries in an apc/realm. Returns as a talloc'ed array in
279  * the NULL context via .  Caller must free these. */
280 size_t trp_rtable_get_realm(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAME *realm, TRP_RENTRY **ret)
281 {
282   GHashTable *apc_tbl=NULL;
283   GHashTable *realm_tbl=NULL;
284   size_t len=0;
285   size_t ii=0;
286   GList *entries=NULL;
287   GList *p=NULL;
288
289   apc_tbl=g_hash_table_lookup(rtbl, apc);
290   if (apc_tbl==NULL)
291     return 0;
292   realm_tbl=g_hash_table_lookup(apc_tbl, realm);
293   if (realm_tbl==NULL)
294     return 0;
295   entries=g_hash_table_get_values(realm_tbl);
296   len=g_hash_table_size(realm_tbl);
297   *ret=talloc_array(NULL, TRP_RENTRY, len);
298   if (*ret==NULL) {
299     tr_crit("trp_rtable_get_realm: could not allocate return array.");
300     return 0;
301   }
302   for (ii=0,p=entries; p!=NULL; ii++,p=g_list_next(p))
303     memcpy(*ret+ii, p->data, sizeof(TRP_RENTRY));
304   g_list_free(entries);
305   return len;
306 }
307
308 /* Gets a single entry, in the NULL talloc context. Caller must free. */
309 TRP_RENTRY *trp_rtable_get_entry(TRP_RTABLE *rtbl, TR_NAME *apc, TR_NAME *realm, TR_NAME *peer)
310 {
311   GHashTable *apc_tbl=NULL;
312   GHashTable *realm_tbl=NULL;
313   
314   apc_tbl=g_hash_table_lookup(rtbl, apc);
315   if (apc_tbl==NULL)
316     return NULL;
317   realm_tbl=g_hash_table_lookup(apc_tbl, realm);
318   if (realm_tbl==NULL)
319     return NULL;
320   return (TRP_RENTRY *)g_hash_table_lookup(realm_tbl, peer);
321 }