]> git.meshlink.io Git - catta/blob - avahi-daemon/static-hosts.c
34f531f4998c25610de7c6954f679741dd42003a
[catta] / avahi-daemon / static-hosts.c
1 /***
2   This file is part of avahi.
3
4   avahi is free software; you can redistribute it and/or modify it
5   under the terms of the GNU Lesser General Public License as
6   published by the Free Software Foundation; either version 2.1 of the
7   License, or (at your option) any later version.
8
9   avahi is distributed in the hope that it will be useful, but WITHOUT
10   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
11   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
12   Public License for more details.
13
14   You should have received a copy of the GNU Lesser General Public
15   License along with avahi; if not, write to the Free Software
16   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
17   USA.
18 ***/
19
20 #ifdef HAVE_CONFIG_H
21 #include <config.h>
22 #endif
23
24 #include <string.h>
25 #include <errno.h>
26 #include <stdio.h>
27
28 #include <avahi-common/llist.h>
29 #include <avahi-common/malloc.h>
30 #include <avahi-common/error.h>
31 #include <avahi-core/log.h>
32 #include <avahi-core/publish.h>
33
34 #include "main.h"
35 #include "static-hosts.h"
36
37 typedef struct StaticHost StaticHost;
38
39 struct StaticHost {
40     AvahiSEntryGroup *group;
41     int iteration;
42
43     char *host;
44     AvahiAddress address;
45
46     AVAHI_LLIST_FIELDS(StaticHost, hosts);
47 };
48
49 static AVAHI_LLIST_HEAD(StaticHost, hosts) = NULL;
50 static int current_iteration = 0;
51
52 static void add_static_host_to_server(StaticHost *h);
53 static void remove_static_host_from_server(StaticHost *h);
54
55 static void entry_group_callback(AvahiServer *s, AVAHI_GCC_UNUSED AvahiSEntryGroup *eg, AvahiEntryGroupState state, void* userdata) {
56     StaticHost *h;
57
58     assert(s);
59     assert(eg);
60
61     h = userdata;
62
63     switch (state) {
64
65         case AVAHI_ENTRY_GROUP_COLLISION:
66             avahi_log_error("Host name conflict for \"%s\", not established.", h->host);
67             break;
68
69         case AVAHI_ENTRY_GROUP_ESTABLISHED:
70             avahi_log_notice ("Static host name \"%s\" successfully established.", h->host);
71             break;
72
73         case AVAHI_ENTRY_GROUP_FAILURE:
74             avahi_log_notice ("Failed to establish static host name \"%s\": %s.", h->host, avahi_strerror (avahi_server_errno (s)));
75             break;
76
77         case AVAHI_ENTRY_GROUP_UNCOMMITED:
78         case AVAHI_ENTRY_GROUP_REGISTERING:
79             ;
80     }
81 }
82
83 static StaticHost *static_host_new(void) {
84     StaticHost *s;
85
86     s = avahi_new(StaticHost, 1);
87
88     s->group = NULL;
89     s->host = NULL;
90     s->iteration = current_iteration;
91
92     AVAHI_LLIST_PREPEND(StaticHost, hosts, hosts, s);
93
94     return s;
95 }
96
97 static void static_host_free(StaticHost *s) {
98     assert(s);
99
100     AVAHI_LLIST_REMOVE(StaticHost, hosts, hosts, s);
101
102     if (s->group)
103         avahi_s_entry_group_free (s->group);
104
105     avahi_free(s->host);
106
107     avahi_free(s);
108 }
109
110 static StaticHost *static_host_find(const char *host, const AvahiAddress *a) {
111     StaticHost *h;
112
113     assert(host);
114     assert(a);
115
116     for (h = hosts; h; h = h->hosts_next)
117         if (!strcmp(h->host, host) && !avahi_address_cmp(a, &h->address))
118             return h;
119
120     return NULL;
121 }
122
123 static void add_static_host_to_server(StaticHost *h)
124 {
125
126     if (!h->group)
127         if (!(h->group = avahi_s_entry_group_new (avahi_server, entry_group_callback, h))) {
128             avahi_log_error("avahi_s_entry_group_new() failed: %s", avahi_strerror(avahi_server_errno(avahi_server)));
129             return;
130         }
131
132     if (avahi_s_entry_group_is_empty(h->group)) {
133         AvahiProtocol p;
134         int err;
135         const AvahiServerConfig *config;
136         config = avahi_server_get_config(avahi_server);
137
138         p = (h->address.proto == AVAHI_PROTO_INET && config->publish_a_on_ipv6) ||
139             (h->address.proto == AVAHI_PROTO_INET6 && config->publish_aaaa_on_ipv4) ? AVAHI_PROTO_UNSPEC : h->address.proto;
140
141         if ((err = avahi_server_add_address(avahi_server, h->group, AVAHI_IF_UNSPEC, p, 0, h->host, &h->address)) < 0) {
142             avahi_log_error ("Static host name %s: avahi_server_add_address failure: %s", h->host, avahi_strerror(err));
143             return;
144         }
145
146         avahi_s_entry_group_commit (h->group);
147     }
148 }
149
150 static void remove_static_host_from_server(StaticHost *h)
151 {
152     if (h->group)
153         avahi_s_entry_group_reset (h->group);
154 }
155
156 void static_hosts_add_to_server(void) {
157     StaticHost *h;
158
159     for (h = hosts; h; h = h->hosts_next)
160         add_static_host_to_server(h);
161 }
162
163 void static_hosts_remove_from_server(void) {
164     StaticHost *h;
165
166     for (h = hosts; h; h = h->hosts_next)
167         remove_static_host_from_server(h);
168 }
169
170 void static_hosts_load(int in_chroot) {
171     FILE *f;
172     unsigned int line = 0;
173     StaticHost *h, *next;
174     const char *filename = in_chroot ? "/hosts" : AVAHI_CONFIG_DIR "/hosts";
175
176     if (!(f = fopen(filename, "r"))) {
177         if (errno != ENOENT)
178             avahi_log_error ("Failed to open static hosts file: %s", strerror (errno));
179         return;
180     }
181
182     current_iteration++;
183
184     while (!feof(f)) {
185         unsigned int len;
186         char ln[256], *s;
187         char *host, *ip;
188         AvahiAddress a;
189
190         if (!fgets(ln, sizeof (ln), f))
191             break;
192
193         line++;
194
195         /* Find the start of the line, ignore whitespace */
196         s = ln + strspn(ln, " \t");
197         /* Set the end of the string to NULL */
198         s[strcspn(s, "#\r\n")] = 0;
199
200         /* Ignore blank lines */
201         if (*s == 0)
202             continue;
203
204         /* Read the first string (ip) up to the next whitespace */
205         len = strcspn(s, " \t");
206         ip = avahi_strndup(s, len);
207
208         /* Skip past it */
209         s += len;
210
211         /* Find the next token */
212         s += strspn(s, " \t");
213         len = strcspn(s, " \t");
214         host = avahi_strndup(s, len);
215
216         if (*host == 0)
217         {
218             avahi_log_error("%s:%d: Error, unexpected end of line!", filename, line);
219             avahi_free(host);
220             avahi_free(ip);
221             goto fail;
222         }
223
224         /* Skip over the host */
225         s += len;
226
227         /* Skip past any more spaces */
228         s += strspn(s, " \t");
229
230         /* Anything left? */
231         if (*s != 0) {
232             avahi_log_error ("%s:%d: Junk on the end of the line!", filename, line);
233             avahi_free(host);
234             avahi_free(ip);
235             goto fail;
236         }
237
238         if (!avahi_address_parse(ip, AVAHI_PROTO_UNSPEC, &a)) {
239             avahi_log_error("Static host name %s: failed to parse address %s", host, ip);
240             avahi_free(host);
241             avahi_free(ip);
242             goto fail;
243         }
244
245         avahi_free(ip);
246
247         if ((h = static_host_find(host, &a)))
248             avahi_free(host);
249         else {
250             h = static_host_new();
251             h->host = host;
252             h->address = a;
253
254             avahi_log_info("Loading new static hostname %s.", h->host);
255         }
256
257         h->iteration = current_iteration;
258     }
259
260     for (h = hosts; h; h = next) {
261         next = h->hosts_next;
262
263         if (h->iteration != current_iteration) {
264             avahi_log_info("Static hostname %s vanished, removing.", h->host);
265             static_host_free(h);
266         }
267     }
268
269 fail:
270
271     fclose(f);
272 }
273
274 void static_hosts_free_all (void)
275 {
276     while(hosts)
277         static_host_free(hosts);
278 }