~davewalker/ubuntu/precise/maas-enlist/avahi-disco

« back to all changes in this revision

Viewing changes to avahi-discover/maas-avahi-discover.c

  • Committer: Dave Walker (Daviey)
  • Date: 2012-03-20 23:17:06 UTC
  • Revision ID: davewalker@ubuntu.com-20120320231706-qy6tkmt3q5fq2rgc
avahi-discover/*: Introduce avahi discovery code, for discovery of a
MAAS service.

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* $Id$ */
 
2
 
 
3
/***
 
4
  This file is based on an example that is part of avahi, which is copyright:
 
5
  Lennart Poettering <lennart (at) poettering (dot) de>
 
6
  Trent Lloyd <lathiat@bur.st>
 
7
  Sebastien Estienne <sebastien.estienne@gmail.com>
 
8
  Jakub Stachowski
 
9
  James Willcox <snorp@snorp.net>
 
10
  Collabora Ltd.
 
11
  Modifications for mass-enlist-udeb are copyright 2009-2012 Canonical Ltd.
 
12
 
 
13
  avahi is free software; you can redistribute it and/or modify it
 
14
  under the terms of the GNU Lesser General Public License as
 
15
  published by the Free Software Foundation; either version 2.1 of the
 
16
  License, or (at your option) any later version.
 
17
 
 
18
  avahi is distributed in the hope that it will be useful, but WITHOUT
 
19
  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
 
20
  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
 
21
  Public License for more details.
 
22
 
 
23
  You should have received a copy of the GNU Lesser General Public
 
24
  License along with avahi; if not, write to the Free Software
 
25
  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
 
26
  USA.
 
27
***/
 
28
 
 
29
#ifdef HAVE_CONFIG_H
 
30
#include <config.h>
 
31
#endif
 
32
 
 
33
#include <stdio.h>
 
34
#include <assert.h>
 
35
#include <stdlib.h>
 
36
#include <time.h>
 
37
#include <string.h>
 
38
 
 
39
#include <avahi-core/core.h>
 
40
#include <avahi-core/lookup.h>
 
41
#include <avahi-core/log.h>
 
42
#include <avahi-common/simple-watch.h>
 
43
#include <avahi-common/malloc.h>
 
44
#include <avahi-common/error.h>
 
45
 
 
46
#include <debian-installer.h>
 
47
 
 
48
static AvahiSimplePoll *simple_poll = NULL;
 
49
static AvahiServer *server = NULL;
 
50
 
 
51
static di_hash_table *resolver_hash = NULL;
 
52
 
 
53
static int debug = 0;
 
54
 
 
55
static void quiet_logger(AvahiLogLevel level, const char *txt) {
 
56
}
 
57
 
 
58
static bool resolver_equal_func(const void *key1, const void *key2) {
 
59
    return !strcmp((const char *) key1, (const char *) key2);
 
60
}
 
61
 
 
62
static uint32_t resolver_hash_func(const void *key) {
 
63
    /* save reimplementing our own hash algorithm ... */
 
64
    di_rstring rstring;
 
65
    rstring.string = (char *) key;
 
66
    rstring.size = strlen(key);
 
67
    return di_rstring_hash(&rstring);
 
68
}
 
69
 
 
70
static void resolve_callback(
 
71
    AvahiSServiceResolver *r,
 
72
    AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
73
    AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
74
    AvahiResolverEvent event,
 
75
    const char *name,
 
76
    const char *type,
 
77
    const char *domain,
 
78
    const char *host_name,
 
79
    const AvahiAddress *address,
 
80
    uint16_t port,
 
81
    AvahiStringList *txt,
 
82
    AvahiLookupResultFlags flags,
 
83
    AVAHI_GCC_UNUSED void* userdata) {
 
84
 
 
85
    assert(r);
 
86
 
 
87
    /* Called whenever a service has been resolved successfully or timed out */
 
88
 
 
89
    switch (event) {
 
90
        case AVAHI_RESOLVER_FAILURE:
 
91
            if (debug)
 
92
                fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_server_errno(server)));
 
93
            break;
 
94
 
 
95
        case AVAHI_RESOLVER_FOUND: {
 
96
            char *human_address = avahi_malloc0(AVAHI_ADDRESS_STR_MAX);
 
97
            char *key = NULL;
 
98
            if (avahi_address_snprint(human_address, AVAHI_ADDRESS_STR_MAX, address)) {
 
99
                if (address->proto == AVAHI_PROTO_INET6)
 
100
                    key = avahi_strdup_printf("[%s]:%u", human_address, port);
 
101
                else if (strncmp(human_address, "169.254.169.254", 15) == 0)
 
102
                    key = avahi_strdup_printf("%s:%u", name, port);
 
103
                else
 
104
                    key = avahi_strdup_printf("%s:%u", human_address, port);
 
105
            } else {
 
106
                if (debug)
 
107
                    fprintf(stderr, "(Resolver) failed to resolve %s to IP address/port\n", key);
 
108
            }
 
109
            avahi_free(human_address);
 
110
 
 
111
            if (di_hash_table_lookup(resolver_hash, key)) {
 
112
                if (debug)
 
113
                    fprintf(stderr, "(Resolver) Already seen %s\n", key);
 
114
                free(key);
 
115
            } else {
 
116
                di_hash_table_insert(resolver_hash, key, "");
 
117
                if (debug)
 
118
                    fprintf(stderr, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
 
119
                printf("%s|%s\n", name, key);
 
120
 
 
121
                }
 
122
                /* don't free key; di_hash_table_insert doesn't copy it */
 
123
            }
 
124
        }
 
125
 
 
126
    avahi_s_service_resolver_free(r);
 
127
}
 
128
 
 
129
static void browse_callback(
 
130
    AvahiSServiceBrowser *b,
 
131
    AvahiIfIndex interface,
 
132
    AvahiProtocol protocol,
 
133
    AvahiBrowserEvent event,
 
134
    const char *name,
 
135
    const char *type,
 
136
    const char *domain,
 
137
    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
138
    void* userdata) {
 
139
 
 
140
    AvahiServer *s = userdata;
 
141
    assert(b);
 
142
 
 
143
    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
 
144
 
 
145
    switch (event) {
 
146
 
 
147
        case AVAHI_BROWSER_FAILURE:
 
148
            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
 
149
            avahi_simple_poll_quit(simple_poll);
 
150
            return;
 
151
 
 
152
        case AVAHI_BROWSER_NEW:
 
153
            if (debug)
 
154
                fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
 
155
 
 
156
            /* We ignore the returned resolver object. In the callback
 
157
               function we free it. If the server is terminated before
 
158
               the callback function is called the server will free
 
159
               the resolver for us. */
 
160
 
 
161
            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_INET, 0, resolve_callback, s)))
 
162
                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
 
163
 
 
164
            break;
 
165
 
 
166
        case AVAHI_BROWSER_REMOVE:
 
167
            if (debug)
 
168
                fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
 
169
            break;
 
170
 
 
171
        case AVAHI_BROWSER_ALL_FOR_NOW:
 
172
            if (debug)
 
173
                fprintf(stderr, "(Browser) %s\n", "ALL_FOR_NOW");
 
174
            exit(0);
 
175
            break;
 
176
 
 
177
        case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
178
            if (debug)
 
179
                fprintf(stderr, "(Browser) %s\n", "CACHE_EXHAUSTED");
 
180
            break;
 
181
    }
 
182
}
 
183
 
 
184
int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
 
185
    AvahiServerConfig config;
 
186
    AvahiSServiceBrowser *sb = NULL;
 
187
    int error;
 
188
    int ret = 1;
 
189
 
 
190
    if (getenv("MAAS_ENLIST_DEBUG"))
 
191
        debug = 1;
 
192
 
 
193
    /* Initialize the pseudo-RNG */
 
194
    srand(time(NULL));
 
195
 
 
196
    if (!debug)
 
197
        avahi_set_log_function(quiet_logger);
 
198
 
 
199
    /* Allocate main loop object */
 
200
    if (!(simple_poll = avahi_simple_poll_new())) {
 
201
        fprintf(stderr, "Failed to create simple poll object.\n");
 
202
        goto fail;
 
203
    }
 
204
 
 
205
    /* Do not publish any local records */
 
206
    avahi_server_config_init(&config);
 
207
    config.publish_hinfo = 0;
 
208
    config.publish_addresses = 0;
 
209
    config.publish_workstation = 0;
 
210
    config.publish_domain = 0;
 
211
 
 
212
    /* Allocate a new server */
 
213
    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
 
214
 
 
215
    /* Free the configuration data */
 
216
    avahi_server_config_free(&config);
 
217
 
 
218
    /* Check whether creating the server object succeeded */
 
219
    if (!server) {
 
220
        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
 
221
        goto fail;
 
222
    }
 
223
 
 
224
    /* Create the service browser */
 
225
    if (!(sb = avahi_s_service_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_maas._tcp", NULL, 0, browse_callback, server))) {
 
226
        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
 
227
        goto fail;
 
228
    }
 
229
 
 
230
    /* Create a hash table so we can uniquify resolver results */
 
231
    resolver_hash = di_hash_table_new_full(resolver_hash_func, resolver_equal_func, avahi_free, NULL);
 
232
 
 
233
    /* Run the main loop */
 
234
    avahi_simple_poll_loop(simple_poll);
 
235
 
 
236
    ret = 0;
 
237
 
 
238
fail:
 
239
 
 
240
    if (resolver_hash)
 
241
        di_hash_table_destroy (resolver_hash);
 
242
 
 
243
    /* Cleanup things */
 
244
    if (sb)
 
245
        avahi_s_service_browser_free(sb);
 
246
 
 
247
    if (server)
 
248
        avahi_server_free(server);
 
249
 
 
250
    if (simple_poll)
 
251
        avahi_simple_poll_free(simple_poll);
 
252
 
 
253
    return ret;
 
254
}