]> git.meshlink.io Git - catta/blob - avahi-utils/avahi-resolve.c
fix avahi_netlink_new to allow multiple netlinks per process
[catta] / avahi-utils / avahi-resolve.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 <stdlib.h>
25 #include <stdio.h>
26 #include <getopt.h>
27 #include <assert.h>
28 #include <string.h>
29 #include <sys/types.h>
30 #include <sys/socket.h>
31 #include <net/if.h>
32 #include <locale.h>
33
34 #include <avahi-common/simple-watch.h>
35 #include <avahi-common/error.h>
36 #include <avahi-common/malloc.h>
37 #include <avahi-common/domain.h>
38 #include <avahi-common/llist.h>
39 #include <avahi-common/i18n.h>
40 #include <avahi-client/client.h>
41 #include <avahi-client/lookup.h>
42
43 #include "sigint.h"
44
45 typedef enum {
46     COMMAND_UNSPEC,
47     COMMAND_HELP,
48     COMMAND_VERSION,
49     COMMAND_RESOLVE_HOST_NAME,
50     COMMAND_RESOLVE_ADDRESS
51 } Command;
52
53 typedef struct Config {
54     int verbose;
55     Command command;
56     AvahiProtocol proto;
57 } Config;
58
59 static AvahiSimplePoll *simple_poll = NULL;
60 static AvahiClient *client = NULL;
61
62 static int n_resolving = 0;
63
64 static void host_name_resolver_callback(
65     AvahiHostNameResolver *r,
66     AVAHI_GCC_UNUSED AvahiIfIndex interface,
67     AVAHI_GCC_UNUSED AvahiProtocol protocol,
68     AvahiResolverEvent event,
69     const char *name,
70     const AvahiAddress *a,
71     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
72     AVAHI_GCC_UNUSED void *userdata) {
73
74     assert(r);
75
76     switch (event) {
77         case AVAHI_RESOLVER_FOUND: {
78             char address[AVAHI_ADDRESS_STR_MAX];
79
80             avahi_address_snprint(address, sizeof(address), a);
81
82             printf("%s\t%s\n", name, address);
83
84             break;
85         }
86
87         case AVAHI_RESOLVER_FAILURE:
88
89             fprintf(stderr, _("Failed to resolve host name '%s': %s\n"), name, avahi_strerror(avahi_client_errno(client)));
90             break;
91     }
92
93
94     avahi_host_name_resolver_free(r);
95
96     assert(n_resolving > 0);
97     n_resolving--;
98
99     if (n_resolving <= 0)
100         avahi_simple_poll_quit(simple_poll);
101 }
102
103 static void address_resolver_callback(
104     AvahiAddressResolver *r,
105     AVAHI_GCC_UNUSED AvahiIfIndex interface,
106     AVAHI_GCC_UNUSED AvahiProtocol protocol,
107     AvahiResolverEvent event,
108     const AvahiAddress *a,
109     const char *name,
110     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
111     AVAHI_GCC_UNUSED void *userdata) {
112
113     char address[AVAHI_ADDRESS_STR_MAX];
114     assert(r);
115
116     avahi_address_snprint(address, sizeof(address), a);
117
118     switch (event) {
119         case AVAHI_RESOLVER_FOUND:
120
121             printf("%s\t%s\n", address, name);
122             break;
123
124         case AVAHI_RESOLVER_FAILURE:
125
126             fprintf(stderr, _("Failed to resolve address '%s': %s\n"), address, avahi_strerror(avahi_client_errno(client)));
127             break;
128     }
129
130
131     avahi_address_resolver_free(r);
132
133     assert(n_resolving > 0);
134     n_resolving--;
135
136     if (n_resolving <= 0)
137         avahi_simple_poll_quit(simple_poll);
138 }
139
140 static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
141     switch (state) {
142         case AVAHI_CLIENT_FAILURE:
143             fprintf(stderr, _("Client failure, exiting: %s\n"), avahi_strerror(avahi_client_errno(c)));
144             avahi_simple_poll_quit(simple_poll);
145             break;
146
147         case AVAHI_CLIENT_S_REGISTERING:
148         case AVAHI_CLIENT_S_RUNNING:
149         case AVAHI_CLIENT_S_COLLISION:
150         case AVAHI_CLIENT_CONNECTING:
151             ;
152     }
153 }
154
155 static void help(FILE *f, const char *argv0) {
156     fprintf(f,
157             _("%s [options] %s <host name ...>\n"
158               "%s [options] %s <address ... >\n\n"
159               "    -h --help            Show this help\n"
160               "    -V --version         Show version\n"
161               "    -n --name            Resolve host name\n"
162               "    -a --address         Resolve address\n"
163               "    -v --verbose         Enable verbose mode\n"
164               "    -6                   Lookup IPv6 address\n"
165               "    -4                   Lookup IPv4 address\n"),
166             argv0, strstr(argv0, "host-name") ? "[-n]" : "-n",
167             argv0, strstr(argv0, "address") ? "[-a]" : "-a");
168 }
169
170 static int parse_command_line(Config *c, const char *argv0, int argc, char *argv[]) {
171     int o;
172
173     static const struct option long_options[] = {
174         { "help",           no_argument,       NULL, 'h' },
175         { "version",        no_argument,       NULL, 'V' },
176         { "name",           no_argument,       NULL, 'n' },
177         { "address",        no_argument,       NULL, 'a' },
178         { "verbose",        no_argument,       NULL, 'v' },
179         { NULL, 0, NULL, 0 }
180     };
181
182     assert(c);
183
184     c->command = strstr(argv0, "address") ? COMMAND_RESOLVE_ADDRESS : (strstr(argv0, "host-name") ? COMMAND_RESOLVE_HOST_NAME : COMMAND_UNSPEC);
185     c->proto = AVAHI_PROTO_UNSPEC;
186     c->verbose = 0;
187
188     while ((o = getopt_long(argc, argv, "hVnav46", long_options, NULL)) >= 0) {
189
190         switch(o) {
191             case 'h':
192                 c->command = COMMAND_HELP;
193                 break;
194             case 'V':
195                 c->command = COMMAND_VERSION;
196                 break;
197             case 'n':
198                 c->command = COMMAND_RESOLVE_HOST_NAME;
199                 break;
200             case 'a':
201                 c->command = COMMAND_RESOLVE_ADDRESS;
202                 break;
203             case 'v':
204                 c->verbose = 1;
205                 break;
206             case '4':
207                 c->proto = AVAHI_PROTO_INET;
208                 break;
209             case '6':
210                 c->proto = AVAHI_PROTO_INET6;
211                 break;
212             default:
213                 return -1;
214         }
215     }
216
217     if (c->command == COMMAND_RESOLVE_ADDRESS || c->command == COMMAND_RESOLVE_HOST_NAME) {
218         if (optind >= argc) {
219             fprintf(stderr, _("Too few arguments\n"));
220             return -1;
221         }
222     }
223
224     return 0;
225 }
226
227 int main(int argc, char *argv[]) {
228     int ret = 1, error;
229     Config config;
230     const char *argv0;
231
232     avahi_init_i18n();
233     setlocale(LC_ALL, "");
234
235     if ((argv0 = strrchr(argv[0], '/')))
236         argv0++;
237     else
238         argv0 = argv[0];
239
240     if (parse_command_line(&config, argv0, argc, argv) < 0)
241         goto fail;
242
243     switch (config.command) {
244         case COMMAND_UNSPEC:
245             ret = 1;
246             fprintf(stderr, _("No command specified.\n"));
247             break;
248
249         case COMMAND_HELP:
250             help(stdout, argv0);
251             ret = 0;
252             break;
253
254         case COMMAND_VERSION:
255             printf("%s "PACKAGE_VERSION"\n", argv0);
256             ret = 0;
257             break;
258
259         case COMMAND_RESOLVE_HOST_NAME:
260         case COMMAND_RESOLVE_ADDRESS: {
261             int i;
262
263             if (!(simple_poll = avahi_simple_poll_new())) {
264                 fprintf(stderr, _("Failed to create simple poll object.\n"));
265                 goto fail;
266             }
267
268             if (sigint_install(simple_poll) < 0)
269                 goto fail;
270
271             if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error))) {
272                 fprintf(stderr, _("Failed to create client object: %s\n"), avahi_strerror(error));
273                 goto fail;
274             }
275
276             if (config.verbose) {
277                 const char *version, *hn;
278
279                 if (!(version = avahi_client_get_version_string(client))) {
280                     fprintf(stderr, _("Failed to query version string: %s\n"), avahi_strerror(avahi_client_errno(client)));
281                     goto fail;
282                 }
283
284                 if (!(hn = avahi_client_get_host_name_fqdn(client))) {
285                     fprintf(stderr, _("Failed to query host name: %s\n"), avahi_strerror(avahi_client_errno(client)));
286                     goto fail;
287                 }
288
289                 fprintf(stderr, _("Server version: %s; Host name: %s\n"), version, hn);
290             }
291
292             n_resolving = 0;
293
294             for (i = optind; i < argc; i++) {
295
296                 if (config.command == COMMAND_RESOLVE_HOST_NAME) {
297
298                     if (!(avahi_host_name_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, argv[i], config.proto, 0, host_name_resolver_callback, NULL))) {
299                         fprintf(stderr, _("Failed to create host name resolver: %s\n"), avahi_strerror(avahi_client_errno(client)));
300                         goto fail;
301                     }
302
303                 } else {
304                     AvahiAddress a;
305
306                     assert(config.command == COMMAND_RESOLVE_ADDRESS);
307
308                     if (!avahi_address_parse(argv[i], AVAHI_PROTO_UNSPEC, &a)) {
309                         fprintf(stderr, _("Failed to parse address '%s'\n"), argv[i]);
310                         goto fail;
311                     }
312
313                     if (!(avahi_address_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, &a, 0, address_resolver_callback, NULL))) {
314                         fprintf(stderr, _("Failed to create address resolver: %s\n"), avahi_strerror(avahi_client_errno(client)));
315                         goto fail;
316                     }
317                 }
318
319                 n_resolving++;
320             }
321
322             avahi_simple_poll_loop(simple_poll);
323             ret = 0;
324             break;
325         }
326     }
327
328 fail:
329
330     if (client)
331         avahi_client_free(client);
332
333     sigint_uninstall();
334
335     if (simple_poll)
336         avahi_simple_poll_free(simple_poll);
337
338     return ret;
339 }