]> git.meshlink.io Git - catta/blob - avahi-utils/avahi-resolve-host-name.c
6a35f1b383b0bceb15fbe209105de3d50564522d
[catta] / avahi-utils / avahi-resolve-host-name.c
1 /* $Id$ */
2
3 /***
4   This file is part of avahi.
5  
6   avahi is free software; you can redistribute it and/or modify it
7   under the terms of the GNU Lesser General Public License as
8   published by the Free Software Foundation; either version 2.1 of the
9   License, or (at your option) any later version.
10  
11   avahi is distributed in the hope that it will be useful, but WITHOUT
12   ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
13   or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
14   Public License for more details.
15  
16   You should have received a copy of the GNU Lesser General Public
17   License along with avahi; if not, write to the Free Software
18   Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
19   USA.
20 ***/
21
22 #ifdef HAVE_CONFIG_H
23 #include <config.h>
24 #endif
25
26 #include <stdlib.h>
27 #include <stdio.h>
28 #include <getopt.h>
29 #include <assert.h>
30 #include <string.h>
31 #include <sys/types.h>
32 #include <sys/socket.h>
33 #include <net/if.h>
34 #include <locale.h>
35
36 #include <avahi-common/simple-watch.h>
37 #include <avahi-common/error.h>
38 #include <avahi-common/malloc.h>
39 #include <avahi-common/domain.h>
40 #include <avahi-common/llist.h>
41 #include <avahi-client/client.h>
42 #include <avahi-client/lookup.h>
43
44 #include "sigint.h"
45
46 #ifdef HAVE_GDBM
47 #include "stdb.h"
48 #endif
49
50 typedef enum {
51     COMMAND_HELP,
52     COMMAND_VERSION,
53     COMMAND_RESOLVE_HOST_NAME,
54     COMMAND_RESOLVE_ADDRESS
55 } Command;
56
57 typedef struct Config {
58     int verbose;
59     Command command;
60     AvahiProtocol proto;
61 } Config;
62
63 static AvahiSimplePoll *simple_poll = NULL;
64 static AvahiClient *client = NULL;
65
66 static int n_resolving = 0;
67
68 static void host_name_resolver_callback(
69     AvahiHostNameResolver *r,
70     AVAHI_GCC_UNUSED AvahiIfIndex interface,
71     AVAHI_GCC_UNUSED AvahiProtocol protocol,
72     AvahiResolverEvent event,
73     const char *name,
74     const AvahiAddress *a,
75     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
76     AVAHI_GCC_UNUSED void *userdata) {
77     
78     assert(r);
79
80     switch (event) {
81         case AVAHI_RESOLVER_FOUND: {
82             char address[AVAHI_ADDRESS_STR_MAX];
83
84             avahi_address_snprint(address, sizeof(address), a);
85
86             printf("%s\t%s\n", name, address);
87             
88             break;
89         }
90
91         case AVAHI_RESOLVER_FAILURE:
92             
93             fprintf(stderr, "Failed to resolve host name '%s': %s\n", name, avahi_strerror(avahi_client_errno(client)));
94             break;
95     }
96
97     
98     avahi_host_name_resolver_free(r);
99
100     assert(n_resolving > 0);
101     n_resolving--;
102
103     if (n_resolving <= 0)
104         avahi_simple_poll_quit(simple_poll);
105 }
106
107 static void address_resolver_callback(
108     AvahiAddressResolver *r,
109     AVAHI_GCC_UNUSED AvahiIfIndex interface,
110     AVAHI_GCC_UNUSED AvahiProtocol protocol,
111     AvahiResolverEvent event,
112     const AvahiAddress *a,
113     const char *name,
114     AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
115     AVAHI_GCC_UNUSED void *userdata) {
116     
117     char address[AVAHI_ADDRESS_STR_MAX];
118     assert(r);
119
120     avahi_address_snprint(address, sizeof(address), a);
121
122     switch (event) {
123         case AVAHI_RESOLVER_FOUND:
124
125             printf("%s\t%s\n", address, name);
126             break;
127
128         case AVAHI_RESOLVER_FAILURE:
129             
130             fprintf(stderr, "Failed to resolve address '%s': %s\n", address, avahi_strerror(avahi_client_errno(client)));
131             break;
132     }
133
134     
135     avahi_address_resolver_free(r);
136
137     assert(n_resolving > 0);
138     n_resolving--;
139
140     if (n_resolving <= 0)
141         avahi_simple_poll_quit(simple_poll);
142 }
143
144 static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
145     switch (state) {
146         case AVAHI_CLIENT_FAILURE:
147             fprintf(stderr, "Client failure, exiting: %s\n", avahi_strerror(avahi_client_errno(c)));
148             avahi_simple_poll_quit(simple_poll);
149             break;
150             
151         case AVAHI_CLIENT_DISCONNECTED:
152             fprintf(stderr, "Client disconnected, exiting.\n");
153             avahi_simple_poll_quit(simple_poll);
154             break;
155
156         case AVAHI_CLIENT_S_REGISTERING:
157         case AVAHI_CLIENT_S_RUNNING:
158         case AVAHI_CLIENT_S_COLLISION:
159             ;
160     }
161 }
162
163 static void help(FILE *f, const char *argv0) {
164     fprintf(f,
165             "%s [options] %s <name ...>\n"
166             "%s [options] %s <address ... >\n\n"
167             "    -h --help            Show this help\n"
168             "    -V --version         Show version\n"
169             "    -n --name            Resolve host name\n"
170             "    -a --address         Resolve address\n"
171             "    -v --verbose         Enable verbose mode\n"
172             "    -6                   Lookup IPv6 address\n"
173             "    -4                   Lookup IPv4 address\n"
174             ,
175             argv0, strstr(argv0, "address") ? "-n" : "[-n]",
176             argv0, strstr(argv0, "address") ? "[-a]" : "-a");
177 }
178
179 static int parse_command_line(Config *c, int argc, char *argv[]) {
180     int o;
181
182     static const struct option long_options[] = {
183         { "help",           no_argument,       NULL, 'h' },
184         { "version",        no_argument,       NULL, 'V' },
185         { "name",           no_argument,       NULL, 'n' },
186         { "address",        no_argument,       NULL, 'a' },
187         { "verbose",        no_argument,       NULL, 'v' },
188         { NULL, 0, NULL, 0 }
189     };
190
191     assert(c);
192
193     c->command = strstr(argv[0], "address") ? COMMAND_RESOLVE_ADDRESS : COMMAND_RESOLVE_HOST_NAME;
194     c->proto = AVAHI_PROTO_UNSPEC;
195     c->verbose = 0;
196
197     opterr = 0;
198     while ((o = getopt_long(argc, argv, "hVnav46", long_options, NULL)) >= 0) {
199
200         switch(o) {
201             case 'h':
202                 c->command = COMMAND_HELP;
203                 break;
204             case 'V':
205                 c->command = COMMAND_VERSION;
206                 break;
207             case 'n':
208                 c->command = COMMAND_RESOLVE_HOST_NAME;
209                 break;
210             case 'a':
211                 c->command = COMMAND_RESOLVE_ADDRESS;
212                 break;
213             case 'v':
214                 c->verbose = 1;
215                 break;
216             case '4':
217                 c->proto = AVAHI_PROTO_INET;
218                 break;
219             case '6':
220                 c->proto = AVAHI_PROTO_INET6;
221                 break;
222             default:
223                 fprintf(stderr, "Invalid command line argument: %c\n", o);
224                 return -1;
225         }
226     }
227
228     if (c->command == COMMAND_RESOLVE_ADDRESS || c->command == COMMAND_RESOLVE_HOST_NAME) {
229         if (optind >= argc) {
230             fprintf(stderr, "Too few arguments\n");
231             return -1;
232         }
233     }
234         
235     return 0;
236 }
237
238 int main(int argc, char *argv[]) {
239     int ret = 1, error;
240     Config config;
241     const char *argv0;
242
243     if ((argv0 = strrchr(argv[0], '/')))
244         argv0++;
245     else
246         argv0 = argv[0];
247
248     if (parse_command_line(&config, argc, argv) < 0)
249         goto fail;
250
251     switch (config.command) {
252         case COMMAND_HELP:
253             help(stdout, argv0);
254             ret = 0;
255             break;
256             
257         case COMMAND_VERSION:
258             printf("%s "PACKAGE_VERSION"\n", argv0);
259             ret = 0;
260             break;
261
262         case COMMAND_RESOLVE_HOST_NAME:
263         case COMMAND_RESOLVE_ADDRESS: {
264             int i;
265             
266             if (!(simple_poll = avahi_simple_poll_new())) {
267                 fprintf(stderr, "Failed to create simple poll object.\n");
268                 goto fail;
269             }
270             
271             if (sigint_install(simple_poll) < 0)
272                 goto fail;
273             
274             if (!(client = avahi_client_new(avahi_simple_poll_get(simple_poll), client_callback, NULL, &error))) {
275                 fprintf(stderr, "Failed to create client object: %s\n", avahi_strerror(error));
276                 goto fail;
277             }
278
279             if (config.verbose) {
280                 const char *version, *hn;
281
282                 if (!(version = avahi_client_get_version_string(client))) {
283                     fprintf(stderr, "Failed to query version string: %s\n", avahi_strerror(avahi_client_errno(client)));
284                     goto fail;
285                 }
286
287                 if (!(hn = avahi_client_get_host_name_fqdn(client))) {
288                     fprintf(stderr, "Failed to query host name: %s\n", avahi_strerror(avahi_client_errno(client)));
289                     goto fail;
290                 }
291                 
292                 fprintf(stderr, "Server version: %s; Host name: %s\n", version, hn);
293             }
294
295             n_resolving = 0;
296             
297             for (i = optind; i < argc; i++) {
298
299                 if (config.command == COMMAND_RESOLVE_HOST_NAME) {
300
301                     if (!(avahi_host_name_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, argv[i], config.proto, 0, host_name_resolver_callback, NULL))) {
302                         fprintf(stderr, "Failed to create host name resolver: %s\n", avahi_strerror(avahi_client_errno(client)));
303                         goto fail;
304                     }
305                         
306                 } else {
307                     AvahiAddress a;
308                     
309                     assert(config.command == COMMAND_RESOLVE_ADDRESS);
310
311                     if (!avahi_address_parse(argv[i], AVAHI_PROTO_UNSPEC, &a)) {
312                         fprintf(stderr, "Failed to parse address '%s'\n", argv[i]);
313                         goto fail;
314                     }
315
316                     if (!(avahi_address_resolver_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, &a, 0, address_resolver_callback, NULL))) {
317                         fprintf(stderr, "Failed to create address resolver: %s\n", avahi_strerror(avahi_client_errno(client)));
318                         goto fail;
319                     }
320                 }
321
322                 n_resolving++;
323             }
324             
325             avahi_simple_poll_loop(simple_poll);
326             ret = 0;
327             break;
328         }
329     }
330     
331     
332 fail:
333
334     if (client)
335         avahi_client_free(client);
336
337     sigint_uninstall();
338     
339     if (simple_poll)
340         avahi_simple_poll_free(simple_poll);
341
342     return ret;
343 }