]> git.meshlink.io Git - catta/blob - local.c
initial commit
[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     flxServer *server;
17     flxAddress address;
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, sizeof(a->family) + flx_address_get_size(a));
46 }
47
48 static void add_addr(flxLocalAddrSource *l, const flxInterfaceAddress *a) {
49     addr_info *ai;
50     gchar *r;
51     g_assert(l);
52     g_assert(a);
53
54     if (!(a->interface->flags & IFF_UP) ||
55         !(a->interface->flags & IFF_RUNNING) ||
56         (a->interface->flags & IFF_LOOPBACK))
57         return;
58
59     if (a->scope != RT_SCOPE_UNIVERSE)
60         return;
61     
62     ai = g_new(addr_info, 1);
63     ai->server = l->server;
64     ai->address = a->address;
65     
66     ai->id = flx_server_get_next_id(l->server);
67     flx_server_add(l->server, ai->id, l->hostname,
68                    ai->address.family == AF_INET ? FLX_DNS_TYPE_A : FLX_DNS_TYPE_AAAA,
69                    ai->address.data, flx_address_get_size(&ai->address));
70
71     r = flx_reverse_lookup_name(&ai->address);
72     flx_server_add(l->server, ai->id, r,
73                    FLX_DNS_TYPE_PTR,
74                    l->hostname, strlen(l->hostname)+1);
75     g_free(r);
76
77     g_hash_table_replace(l->hash_table, &ai->address, ai);
78
79 }
80
81 /* Called whenever a new address becomes available, is changed or removed on the local machine */
82 static void addr_callback(flxInterfaceMonitor *m, flxInterfaceChange change, const flxInterfaceAddress *a, gpointer userdata) {
83     flxLocalAddrSource *l = userdata;
84     g_assert(m);
85     g_assert(a);
86     g_assert(l);
87
88     if (change == FLX_INTERFACE_REMOVE)
89         g_hash_table_remove(l->hash_table, &a->address);
90     else if (change == FLX_INTERFACE_NEW)
91         add_addr(l, a);
92 }
93
94 static void destroy(gpointer data) {
95     addr_info *ai = data;
96     flx_server_remove(ai->server, ai->id);
97     g_free(ai);
98 }
99
100 flxLocalAddrSource *flx_local_addr_source_new(flxServer *s) {
101     flxLocalAddrSource *l;
102     const flxInterface *i;
103     struct utsname utsname;
104     gint length;
105     gchar *e, *hn, *c;
106
107     l = g_new(flxLocalAddrSource, 1);
108     l->server = s;
109     l->hash_table = g_hash_table_new_full(addr_hash, addr_equal, NULL, destroy);
110
111     hn = flx_get_host_name();
112     if ((e = strchr(hn, '.')))
113         *e = 0;
114
115     l->hostname = g_strdup_printf("%s.local.", hn);
116     g_free(hn);
117
118     flx_interface_monitor_add_address_callback(s->monitor, addr_callback, l);
119
120     for (i = flx_interface_monitor_get_first(s->monitor); i; i = i->next) {
121         flxInterfaceAddress *a;
122
123         for (a = i->addresses; a; a = a->next)
124             add_addr(l, a);
125     }
126
127     l->hinfo_id = flx_server_get_next_id(l->server);
128
129     uname(&utsname);
130     c = g_strdup_printf("%s%c%s%n", g_strup(utsname.machine), 0, g_strup(utsname.sysname), &length);
131     
132     flx_server_add(l->server, l->hinfo_id, l->hostname,
133                    FLX_DNS_TYPE_HINFO,
134                    c, length+1);
135     g_free(c);
136     
137     return l;
138 }
139
140 void flx_local_addr_source_free(flxLocalAddrSource *l) {
141     g_assert(l);
142     
143     flx_interface_monitor_remove_address_callback(l->server->monitor, addr_callback, l);
144     g_hash_table_destroy(l->hash_table);
145     flx_server_remove(l->server, l->hinfo_id);
146     g_free(l->hostname);
147     g_free(l);
148 }