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