]> git.meshlink.io Git - catta/blob - local.c
add prioq abstract data type
[catta] / local.c
1 #include <sys/socket.h>
2 #include <asm/types.h>
3 #include <linux/netlink.h>
4 #include <linux/rtnetlink.h>
5 #include <string.h>
6 #include <sys/socket.h>
7 #include <sys/utsname.h>
8 #include <net/if.h>
9
10 #include "flx.h"
11 #include "server.h"
12 #include "util.h"
13 #include "iface.h"
14
15 typedef struct {
16     flxAddress address;
17     flxServer *server;
18     gint id;
19 } addr_info;
20
21 struct _flxLocalAddrSource {
22     flxServer *server;
23     GHashTable *hash_table;
24     gint hinfo_id;
25     gchar *hostname;
26 };
27
28 static gboolean addr_equal(gconstpointer a, gconstpointer b) {
29     return flx_address_cmp(a, b) == 0;
30 }
31
32 static guint hash(gconstpointer v, guint l) {
33     const guint8 *c;
34     guint hash = 0;
35
36     for (c = v; l > 0; c++, l--)
37         hash = 31 * hash + *c;
38
39     return hash;
40 }
41
42 static guint addr_hash(gconstpointer v) {
43     const flxAddress *a = v;
44
45     return hash(a->data, flx_address_get_size(a));
46 }
47
48 static void remove_addr(flxLocalAddrSource *l, const flxInterfaceAddress *a) {
49     flxAddress foo;
50     g_assert(l);
51     g_assert(a);
52
53     memset(&foo, 0, sizeof(foo));
54     foo.family = AF_INET;
55
56     g_hash_table_remove(l->hash_table, &foo); 
57 }
58
59 static void add_addr(flxLocalAddrSource *l, const flxInterfaceAddress *a) {
60     addr_info *ai;
61     g_assert(l);
62     g_assert(a);
63
64     if (g_hash_table_lookup(l->hash_table, &a->address))
65         return; /* Entry already existant */
66
67     ai = g_new(addr_info, 1);
68     ai->server = l->server;
69     ai->address = a->address;
70     
71     ai->id = flx_server_get_next_id(l->server);
72
73     flx_server_add_address(l->server, ai->id, a->interface->index, AF_UNSPEC, l->hostname, &ai->address);
74
75     g_hash_table_replace(l->hash_table, &ai->address, ai);
76 }
77
78 static void handle_addr(flxLocalAddrSource *l, const flxInterfaceAddress *a) {
79     g_assert(l);
80     g_assert(a);
81
82     if (!(a->interface->flags & IFF_UP) ||
83         !(a->interface->flags & IFF_RUNNING) ||
84         (a->interface->flags & IFF_LOOPBACK) ||
85         a->scope != RT_SCOPE_UNIVERSE)
86
87         remove_addr(l, a);
88     else
89         add_addr(l, a);
90 }
91
92 /* Called whenever a new address becomes available, is changed or removed on the local machine */
93 static void addr_callback(flxInterfaceMonitor *m, flxInterfaceChange change, const flxInterfaceAddress *a, gpointer userdata) {
94     flxLocalAddrSource *l = userdata;
95     g_assert(m);
96     g_assert(a);
97     g_assert(l);
98
99     if (change == FLX_INTERFACE_REMOVE)
100         remove_addr(l, a);
101     else 
102         handle_addr(l, a);
103 }
104
105 /* Called whenever a new interface becomes available, is changed or removed on the local machine */
106 static void interface_callback(flxInterfaceMonitor *m, flxInterfaceChange change, const flxInterface *i, gpointer userdata) {
107     flxLocalAddrSource *l = userdata;
108     g_assert(m);
109     g_assert(i);
110     g_assert(l);
111
112     if (change == FLX_INTERFACE_CHANGE) {
113         flxInterfaceAddress *a;
114
115         for (a = i->addresses; a; a = a->next)
116             handle_addr(l, a);
117     }
118 }
119
120 static void destroy(gpointer data) {
121     addr_info *ai = data;
122     flx_server_remove(ai->server, ai->id);
123     g_free(ai);
124 }
125
126 flxLocalAddrSource *flx_local_addr_source_new(flxServer *s) {
127     flxLocalAddrSource *l;
128     const flxInterface *i;
129     struct utsname utsname;
130     gint length;
131     gchar *e, *hn, *c;
132
133     l = g_new(flxLocalAddrSource, 1);
134     l->server = s;
135     l->hash_table = g_hash_table_new_full(addr_hash, addr_equal, NULL, destroy);
136
137     hn = flx_get_host_name();
138     if ((e = strchr(hn, '.')))
139         *e = 0;
140
141     l->hostname = g_strdup_printf("%s.local.", hn);
142     g_free(hn);
143
144     flx_interface_monitor_add_address_callback(s->monitor, addr_callback, l);
145     flx_interface_monitor_add_interface_callback(s->monitor, interface_callback, l);
146
147     for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->next) {
148         flxInterfaceAddress *a;
149
150         for (a = i->addresses; a; a = a->next)
151             add_addr(l, a);
152     }
153
154     l->hinfo_id = flx_server_get_next_id(l->server);
155
156     uname(&utsname);
157     c = g_strdup_printf("%s%c%s%n", g_strup(utsname.machine), 0, g_strup(utsname.sysname), &length);
158     
159     flx_server_add(l->server, l->hinfo_id, 0, AF_UNSPEC,
160                    l->hostname, FLX_DNS_TYPE_HINFO, c, length+1);
161     g_free(c);
162     
163     return l;
164 }
165
166 void flx_local_addr_source_free(flxLocalAddrSource *l) {
167     g_assert(l);
168     
169     flx_interface_monitor_remove_address_callback(l->server->monitor, addr_callback, l);
170     g_hash_table_destroy(l->hash_table);
171     flx_server_remove(l->server, l->hinfo_id);
172     g_free(l->hostname);
173     g_free(l);
174 }