~iheino+ub/+junk/nut-upsconf-docfix

« back to all changes in this revision

Viewing changes to tools/nut-scanner/scan_avahi.c

  • Committer: Tuomas Heino
  • Author(s): Laurent Bigonville
  • Date: 2014-04-22 20:46:12 UTC
  • Revision ID: iheino+ub@cc.hut.fi-20140422204612-1x2gh3nkezfsdao4
Tags: upstream-2.7.2
ImportĀ upstreamĀ versionĀ 2.7.2

Show diffs side-by-side

added added

removed removed

Lines of Context:
 
1
/* scan_avahi.c: detect NUT avahi services
 
2
 * 
 
3
 *  Copyright (C) 2011 - Frederic Bohe <fredericbohe@eaton.com>
 
4
 *
 
5
 *  This program is free software; you can redistribute it and/or modify
 
6
 *  it under the terms of the GNU General Public License as published by
 
7
 *  the Free Software Foundation; either version 2 of the License, or
 
8
 *  (at your option) any later version.
 
9
 *
 
10
 *  This program is distributed in the hope that it will be useful,
 
11
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 
12
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 
13
 *  GNU General Public License for more details.
 
14
 *
 
15
 *  You should have received a copy of the GNU General Public License
 
16
 *  along with this program; if not, write to the Free Software
 
17
 *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
 
18
 */
 
19
#include "common.h"
 
20
#include "nut-scan.h"
 
21
 
 
22
#ifdef WITH_AVAHI
 
23
 
 
24
#include <stdio.h>
 
25
#include <assert.h>
 
26
#include <stdlib.h>
 
27
#include "timehead.h"
 
28
 
 
29
#include <avahi-client/client.h>
 
30
#include <avahi-client/lookup.h>
 
31
 
 
32
#include <avahi-common/simple-watch.h>
 
33
#include <avahi-common/malloc.h>
 
34
#include <avahi-common/error.h>
 
35
 
 
36
#include <ltdl.h>
 
37
 
 
38
/* dynamic link library stuff */
 
39
static char * libname = "libavahi-client";
 
40
static lt_dlhandle dl_handle = NULL;
 
41
static const char *dl_error = NULL;
 
42
 
 
43
static AvahiClient* (*nut_avahi_service_browser_get_client)(AvahiServiceBrowser *);
 
44
static int (*nut_avahi_simple_poll_loop)(AvahiSimplePoll *s);
 
45
static void (*nut_avahi_client_free)(AvahiClient *client);
 
46
static int (*nut_avahi_client_errno)(AvahiClient*);
 
47
static void (*nut_avahi_free)(void *p);
 
48
static void (*nut_avahi_simple_poll_quit)(AvahiSimplePoll *s);
 
49
static AvahiClient* (*nut_avahi_client_new)(
 
50
                const AvahiPoll *poll_api,
 
51
                AvahiClientFlags flags,
 
52
                AvahiClientCallback callback,
 
53
                void *userdata,
 
54
                int *error);
 
55
static void (*nut_avahi_simple_poll_free)(AvahiSimplePoll *s);
 
56
static AvahiServiceResolver * (*nut_avahi_service_resolver_new)(
 
57
                AvahiClient *client,
 
58
                AvahiIfIndex interface,
 
59
                AvahiProtocol protocol,
 
60
                const char *name,
 
61
                const char *type,
 
62
                const char *domain,
 
63
                AvahiProtocol aprotocol,
 
64
                AvahiLookupFlags flags,
 
65
                AvahiServiceResolverCallback callback,
 
66
                void *userdata);
 
67
static const char * (*nut_avahi_strerror)(int error);
 
68
static AvahiClient* (*nut_avahi_service_resolver_get_client)(AvahiServiceResolver *);
 
69
static AvahiServiceBrowser* (*nut_avahi_service_browser_new)(
 
70
                AvahiClient *client,
 
71
                AvahiIfIndex interface,
 
72
                AvahiProtocol protocol,
 
73
                const char *type,
 
74
                const char *domain,
 
75
                AvahiLookupFlags flags,
 
76
                AvahiServiceBrowserCallback callback,
 
77
                void *userdata);
 
78
static int (*nut_avahi_service_resolver_free)(AvahiServiceResolver *r);
 
79
static AvahiSimplePoll *(*nut_avahi_simple_poll_new)(void);
 
80
static char* (*nut_avahi_string_list_to_string)(AvahiStringList *l);
 
81
static int (*nut_avahi_service_browser_free)(AvahiServiceBrowser *);
 
82
static char * (*nut_avahi_address_snprint)(char *ret_s, size_t length, const AvahiAddress *a);
 
83
static const AvahiPoll* (*nut_avahi_simple_poll_get)(AvahiSimplePoll *s);
 
84
 
 
85
/* return 0 on error */
 
86
int nutscan_load_avahi_library()
 
87
{
 
88
        if( dl_handle != NULL ) {
 
89
                /* if previous init failed */
 
90
                if( dl_handle == (void *)1 ) {
 
91
                        return 0;
 
92
                }
 
93
                /* init has already been done */
 
94
                return 1;
 
95
        }
 
96
 
 
97
        if( lt_dlinit() != 0 ) {
 
98
                fprintf(stderr, "Error initializing lt_init\n");
 
99
                return 0;
 
100
        }
 
101
 
 
102
        dl_handle = lt_dlopenext(libname);
 
103
        if (!dl_handle) {
 
104
                dl_error = lt_dlerror();
 
105
                goto err;
 
106
        }
 
107
        lt_dlerror();      /* Clear any existing error */
 
108
        *(void **) (&nut_avahi_service_browser_get_client) = lt_dlsym(dl_handle, "avahi_service_browser_get_client");
 
109
        if ((dl_error = lt_dlerror()) != NULL)  {
 
110
                goto err;
 
111
        }
 
112
 
 
113
        *(void **) (&nut_avahi_simple_poll_loop) = lt_dlsym(dl_handle, "avahi_simple_poll_loop");
 
114
        if ((dl_error = lt_dlerror()) != NULL)  {
 
115
                goto err;
 
116
        }
 
117
 
 
118
        *(void **) (&nut_avahi_client_free) = lt_dlsym(dl_handle, "avahi_client_free");
 
119
        if ((dl_error = lt_dlerror()) != NULL)  {
 
120
                goto err;
 
121
        }
 
122
 
 
123
        *(void **) (&nut_avahi_client_errno) = lt_dlsym(dl_handle, "avahi_client_errno");
 
124
        if ((dl_error = lt_dlerror()) != NULL)  {
 
125
                goto err;
 
126
        }
 
127
 
 
128
        *(void **) (&nut_avahi_free) = lt_dlsym(dl_handle, "avahi_free");
 
129
        if ((dl_error = lt_dlerror()) != NULL)  {
 
130
                goto err;
 
131
        }
 
132
 
 
133
        *(void **) (&nut_avahi_simple_poll_quit) = lt_dlsym(dl_handle, "avahi_simple_poll_quit");
 
134
        if ((dl_error = lt_dlerror()) != NULL)  {
 
135
                goto err;
 
136
        }
 
137
 
 
138
        *(void **) (&nut_avahi_client_new) = lt_dlsym(dl_handle, "avahi_client_new");
 
139
        if ((dl_error = lt_dlerror()) != NULL)  {
 
140
                goto err;
 
141
        }
 
142
 
 
143
        *(void **) (&nut_avahi_simple_poll_free) = lt_dlsym(dl_handle, "avahi_simple_poll_free");
 
144
        if ((dl_error = lt_dlerror()) != NULL)  {
 
145
                goto err;
 
146
        }
 
147
 
 
148
        *(void **) (&nut_avahi_service_resolver_new) = lt_dlsym(dl_handle, "avahi_service_resolver_new");
 
149
        if ((dl_error = lt_dlerror()) != NULL)  {
 
150
                goto err;
 
151
        }
 
152
 
 
153
        *(void **) (&nut_avahi_strerror) = lt_dlsym(dl_handle, "avahi_strerror");
 
154
        if ((dl_error = lt_dlerror()) != NULL)  {
 
155
                goto err;
 
156
        }
 
157
 
 
158
        *(void **) (&nut_avahi_service_resolver_get_client) = lt_dlsym(dl_handle, "avahi_service_resolver_get_client");
 
159
        if ((dl_error = lt_dlerror()) != NULL)  {
 
160
                goto err;
 
161
        }
 
162
 
 
163
        *(void **) (&nut_avahi_service_browser_new) = lt_dlsym(dl_handle, "avahi_service_browser_new");
 
164
        if ((dl_error = lt_dlerror()) != NULL)  {
 
165
                goto err;
 
166
        }
 
167
 
 
168
        *(void **) (&nut_avahi_service_resolver_free) = lt_dlsym(dl_handle, "avahi_service_resolver_free");
 
169
        if ((dl_error = lt_dlerror()) != NULL)  {
 
170
                goto err;
 
171
        }
 
172
 
 
173
        *(void **) (&nut_avahi_simple_poll_new) = lt_dlsym(dl_handle, "avahi_simple_poll_new");
 
174
        if ((dl_error = lt_dlerror()) != NULL)  {
 
175
                goto err;
 
176
        }
 
177
 
 
178
        *(void **) (&nut_avahi_string_list_to_string) = lt_dlsym(dl_handle, "avahi_string_list_to_string");
 
179
        if ((dl_error = lt_dlerror()) != NULL)  {
 
180
                goto err;
 
181
        }
 
182
 
 
183
        *(void **) (&nut_avahi_service_browser_free) = lt_dlsym(dl_handle, "avahi_service_browser_free");
 
184
        if ((dl_error = lt_dlerror()) != NULL)  {
 
185
                goto err;
 
186
        }
 
187
 
 
188
        *(void **) (&nut_avahi_address_snprint) = lt_dlsym(dl_handle, "avahi_address_snprint");
 
189
        if ((dl_error = lt_dlerror()) != NULL)  {
 
190
                goto err;
 
191
        }
 
192
 
 
193
        *(void **) (&nut_avahi_simple_poll_get) = lt_dlsym(dl_handle, "avahi_simple_poll_get");
 
194
        if ((dl_error = lt_dlerror()) != NULL)  {
 
195
                goto err;
 
196
        }
 
197
 
 
198
        return 1;
 
199
err:
 
200
        fprintf(stderr, "Cannot load AVAHI library (%s) : %s. AVAHI search disabled.\n", libname, dl_error);
 
201
 
 
202
        dl_handle = (void *)1;
 
203
        lt_dlexit();
 
204
        return 0;
 
205
}
 
206
/* end of dynamic link library stuff */
 
207
 
 
208
static AvahiSimplePoll *simple_poll = NULL;
 
209
static nutscan_device_t * dev_ret = NULL;
 
210
static long avahi_usec_timeout = 0;
 
211
 
 
212
static void update_device(const char * host_name,const char *ip, uint16_t port,char * text, int proto)
 
213
{
 
214
        nutscan_device_t * dev = NULL;
 
215
 
 
216
        char * t = NULL;
 
217
        char * t_saveptr = NULL;
 
218
        char * phrase = NULL;
 
219
        char * phrase_saveptr = NULL;
 
220
        char * word = NULL;
 
221
        char * value = NULL;
 
222
        char * device = NULL;
 
223
        char * device_saveptr = NULL;
 
224
        int device_found = 0;
 
225
        char buf[6];
 
226
        int buf_size;
 
227
 
 
228
        if( text == NULL ) {
 
229
                return;
 
230
        }
 
231
 
 
232
        t = strdup(text);
 
233
        phrase = strtok_r(t,"\"",&t_saveptr);
 
234
        while(phrase != NULL ) {
 
235
                word = strtok_r(phrase,"=",&phrase_saveptr);
 
236
                if( word == NULL ) {
 
237
                        phrase = strtok_r(NULL,"\"",&t_saveptr);
 
238
                        continue;
 
239
                }
 
240
                value = strtok_r(NULL,"=",&phrase_saveptr);
 
241
                if( value == NULL ) {
 
242
                        phrase = strtok_r(NULL,"\"",&t_saveptr);
 
243
                        continue;
 
244
                }
 
245
 
 
246
                if( strcmp(word,"device_list") != 0 ) {
 
247
                        phrase = strtok_r(NULL,"\"",&t_saveptr);
 
248
                        continue;
 
249
                }
 
250
 
 
251
                device = strtok_r(value,";",&device_saveptr);
 
252
                while( device != NULL ) {
 
253
                        device_found = 1;
 
254
                        dev = nutscan_new_device();
 
255
                        dev->type = TYPE_NUT;
 
256
                        dev->driver = strdup("nutclient");
 
257
                        if( proto == AVAHI_PROTO_INET) {
 
258
                                nutscan_add_option_to_device(dev,"desc","IPv4");
 
259
                        }
 
260
                        if( proto == AVAHI_PROTO_INET6 ) {
 
261
                                nutscan_add_option_to_device(dev,"desc","IPv6");
 
262
                        }
 
263
 
 
264
                        if( port != PORT) {
 
265
                                /* +5+1+1+1 is for : 
 
266
                                 - port number (max 65535 so 5 characters),
 
267
                                 - '@' and ':' characters
 
268
                                 - terminating 0 */
 
269
                                buf_size = strlen(device)+strlen(host_name)+
 
270
                                                5+1+1+1;
 
271
                                dev->port=malloc(buf_size);
 
272
                                if(dev->port) {
 
273
                                        snprintf(dev->port,buf_size,"%s@%s:%u",
 
274
                                                        device,host_name,port);
 
275
                                }
 
276
                        }
 
277
                        else {
 
278
                                /*+1+1 is for '@' character and terminating 0 */
 
279
                                buf_size = strlen(device)+strlen(host_name)+1+1;
 
280
                                dev->port=malloc(buf_size);
 
281
                                if(dev->port) {
 
282
                                        snprintf(dev->port,buf_size,"%s@%s",
 
283
                                                        device,host_name);
 
284
                                }
 
285
                        }
 
286
                        if( dev->port ) {
 
287
                                dev_ret = nutscan_add_device_to_device(dev_ret,dev);
 
288
                        }
 
289
                        else {
 
290
                                nutscan_free_device(dev);
 
291
                        }
 
292
                        device = strtok_r(NULL,";",&device_saveptr);
 
293
                };
 
294
 
 
295
                phrase = strtok_r(NULL,"\"",&t_saveptr);
 
296
        };
 
297
        free(t);
 
298
 
 
299
        /* If no device published in avahi data, try to get the device by
 
300
        connecting directly to upsd */
 
301
        if( !device_found) {
 
302
                snprintf(buf,sizeof(buf),"%u",port);
 
303
                dev = nutscan_scan_nut(ip,ip,buf,avahi_usec_timeout);
 
304
                if(dev) {
 
305
                        dev_ret = nutscan_add_device_to_device(dev_ret,dev);
 
306
                }
 
307
                /* add an upsd entry without associated device */
 
308
                else {
 
309
                        dev = nutscan_new_device();
 
310
                        dev->type = TYPE_NUT;
 
311
                        dev->driver = strdup("nutclient");
 
312
                        if( proto == AVAHI_PROTO_INET) {
 
313
                                nutscan_add_option_to_device(dev,"desc","IPv4");
 
314
                        }
 
315
                        if( proto == AVAHI_PROTO_INET6 ) {
 
316
                                nutscan_add_option_to_device(dev,"desc","IPv6");
 
317
                        }
 
318
                        if( port != PORT) {
 
319
                                /*+1+1 is for ':' character and terminating 0 */
 
320
                                /*buf is the string containing the port number*/
 
321
                                buf_size = strlen(host_name)+strlen(buf)+1+1;
 
322
                                dev->port=malloc(buf_size);
 
323
                                if(dev->port) {
 
324
                                        snprintf(dev->port,buf_size,"%s:%s",
 
325
                                                        host_name,buf);
 
326
                                }
 
327
                        }
 
328
                        else {
 
329
                                dev->port=strdup(host_name);
 
330
                        }
 
331
                        if( dev->port ) {
 
332
                                dev_ret = nutscan_add_device_to_device(dev_ret,dev);
 
333
                        }
 
334
                        else {
 
335
                                nutscan_free_device(dev);
 
336
                        }
 
337
                }
 
338
        }
 
339
}
 
340
 
 
341
static void resolve_callback(
 
342
        AvahiServiceResolver *r,
 
343
        AVAHI_GCC_UNUSED AvahiIfIndex interface,
 
344
        AVAHI_GCC_UNUSED AvahiProtocol protocol,
 
345
        AvahiResolverEvent event,
 
346
        const char *name,
 
347
        const char *type,
 
348
        const char *domain,
 
349
        const char *host_name,
 
350
        const AvahiAddress *address,
 
351
        uint16_t port,
 
352
        AvahiStringList *txt,
 
353
        AvahiLookupResultFlags flags,
 
354
        AVAHI_GCC_UNUSED void* userdata) {
 
355
 
 
356
        assert(r);
 
357
 
 
358
        /* Called whenever a service has been resolved successfully or timed out */
 
359
 
 
360
        switch (event) {
 
361
                case AVAHI_RESOLVER_FAILURE:
 
362
                        fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, (*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_resolver_get_client)(r))));
 
363
                        break;
 
364
 
 
365
                case AVAHI_RESOLVER_FOUND: {
 
366
                        char a[AVAHI_ADDRESS_STR_MAX], *t;
 
367
 
 
368
/*                      fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain); */
 
369
 
 
370
                        (*nut_avahi_address_snprint)(a, sizeof(a), address);
 
371
                        t = (*nut_avahi_string_list_to_string)(txt);
 
372
/*
 
373
                        fprintf(stderr,
 
374
                                "\t%s:%u (%s)\n"
 
375
                                "\tTXT=%s\n"
 
376
                                "\tcookie is %u\n"
 
377
                                "\tis_local: %i\n"
 
378
                                "\tour_own: %i\n"
 
379
                                "\twide_area: %i\n"
 
380
                                "\tmulticast: %i\n"
 
381
                                "\tcached: %i\n",
 
382
                                host_name, port, a,
 
383
                                t,
 
384
                                avahi_string_list_get_service_cookie(txt),
 
385
                                !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
 
386
                                !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
 
387
                                !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
 
388
                                !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
 
389
                                !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
 
390
*/
 
391
                        update_device(host_name,a,port,t,address->proto);
 
392
                        (*nut_avahi_free)(t);
 
393
                }
 
394
        }
 
395
 
 
396
        (*nut_avahi_service_resolver_free)(r);
 
397
}
 
398
 
 
399
static void browse_callback(
 
400
                AvahiServiceBrowser *b,
 
401
                AvahiIfIndex interface,
 
402
                AvahiProtocol protocol,
 
403
                AvahiBrowserEvent event,
 
404
                const char *name,
 
405
                const char *type,
 
406
                const char *domain,
 
407
                AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
 
408
                void* userdata) {
 
409
 
 
410
        AvahiClient *c = userdata;
 
411
        assert(b);
 
412
 
 
413
        /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
 
414
 
 
415
        switch (event) {
 
416
                case AVAHI_BROWSER_FAILURE:
 
417
 
 
418
                        fprintf(stderr, "(Browser) %s\n", (*nut_avahi_strerror)((*nut_avahi_client_errno)((*nut_avahi_service_browser_get_client)(b))));
 
419
                        (*nut_avahi_simple_poll_quit)(simple_poll);
 
420
                        return;
 
421
 
 
422
                case AVAHI_BROWSER_NEW:
 
423
/*                      fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain); */
 
424
 
 
425
                        /* We ignore the returned resolver object. In the callback
 
426
                           function we free it. If the server is terminated before
 
427
                           the callback function is called the server will free
 
428
                           the resolver for us. */
 
429
 
 
430
                        if (!((*nut_avahi_service_resolver_new)(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
 
431
                                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, (*nut_avahi_strerror)((*nut_avahi_client_errno)(c)));
 
432
 
 
433
                        break;
 
434
 
 
435
                case AVAHI_BROWSER_REMOVE:
 
436
                        fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
 
437
                        break;
 
438
 
 
439
                case AVAHI_BROWSER_ALL_FOR_NOW:
 
440
                        (*nut_avahi_simple_poll_quit)(simple_poll);
 
441
                case AVAHI_BROWSER_CACHE_EXHAUSTED:
 
442
/*                      fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW"); */
 
443
                        break;
 
444
        }
 
445
}
 
446
 
 
447
static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
 
448
        assert(c);
 
449
 
 
450
        /* Called whenever the client or server state changes */
 
451
 
 
452
        if (state == AVAHI_CLIENT_FAILURE) {
 
453
                fprintf(stderr, "Server connection failure: %s\n", (*nut_avahi_strerror)((*nut_avahi_client_errno)(c)));
 
454
                (*nut_avahi_simple_poll_quit)(simple_poll);
 
455
        }
 
456
}
 
457
 
 
458
nutscan_device_t * nutscan_scan_avahi(long usec_timeout)
 
459
{
 
460
        /* Example service publication 
 
461
         * $ avahi-publish -s nut _upsd._tcp 3493 txtvers=1 protovers=1.0.0 device_list="dev1;dev2"
 
462
         */
 
463
        AvahiClient *client = NULL;
 
464
        AvahiServiceBrowser *sb = NULL;
 
465
        int error;
 
466
 
 
467
        if( !nutscan_avail_avahi ) {
 
468
                return NULL;
 
469
        }
 
470
 
 
471
        avahi_usec_timeout = usec_timeout;
 
472
 
 
473
        /* Allocate main loop object */
 
474
        if (!(simple_poll = (*nut_avahi_simple_poll_new)())) {
 
475
                fprintf(stderr, "Failed to create simple poll object.\n");
 
476
                goto fail;
 
477
        }
 
478
 
 
479
        /* Allocate a new client */
 
480
        client = (*nut_avahi_client_new)((*nut_avahi_simple_poll_get)(simple_poll), 0, client_callback, NULL, &error);
 
481
 
 
482
        /* Check wether creating the client object succeeded */
 
483
        if (!client) {
 
484
                fprintf(stderr, "Failed to create client: %s\n", (*nut_avahi_strerror)(error));
 
485
                goto fail;
 
486
        }
 
487
 
 
488
        /* Create the service browser */
 
489
        if (!(sb = (*nut_avahi_service_browser_new)(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_upsd._tcp", NULL, 0, browse_callback, client))) {
 
490
                fprintf(stderr, "Failed to create service browser: %s\n", (*nut_avahi_strerror)((*nut_avahi_client_errno)(client)));
 
491
                goto fail;
 
492
        }
 
493
 
 
494
        /* Run the main loop */
 
495
        (*nut_avahi_simple_poll_loop)(simple_poll);
 
496
 
 
497
fail:
 
498
 
 
499
        /* Cleanup things */
 
500
        if (sb)
 
501
                (*nut_avahi_service_browser_free)(sb);
 
502
 
 
503
        if (client)
 
504
                (*nut_avahi_client_free)(client);
 
505
 
 
506
        if (simple_poll)
 
507
                (*nut_avahi_simple_poll_free)(simple_poll);
 
508
 
 
509
        return nutscan_rewind_device(dev_ret);
 
510
}
 
511
#else  /* WITH_AVAHI */
 
512
/* stub function */
 
513
nutscan_device_t * nutscan_scan_avahi(long usec_timeout)
 
514
{
 
515
        return NULL;
 
516
}
 
517
#endif /* WITH_AVAHI */