1/* $Id$ */
2
3/* PLEASE NOTE *
4 * This file demonstrates how to use Avahi's core API, this is
5 * the embeddable mDNS stack for embedded applications.
6 *
7 * End user applications should *not* use this API and should use
8 * the D-Bus or C APIs, please see
9 * client-browse-services.c and glib-integration.c
10 *
11 * I repeat, you probably do *not* want to use this example.
12 */
13
14/***
15  This file is part of avahi.
16
17  avahi is free software; you can redistribute it and/or modify it
18  under the terms of the GNU Lesser General Public License as
19  published by the Free Software Foundation; either version 2.1 of the
20  License, or (at your option) any later version.
21
22  avahi is distributed in the hope that it will be useful, but WITHOUT
23  ANY WARRANTY; without even the implied warranty of MERCHANTABILITY
24  or FITNESS FOR A PARTICULAR PURPOSE. See the GNU Lesser General
25  Public License for more details.
26
27  You should have received a copy of the GNU Lesser General Public
28  License along with avahi; if not, write to the Free Software
29  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
30  USA.
31***/
32
33#ifdef HAVE_CONFIG_H
34#include <config.h>
35#endif
36
37#include <stdio.h>
38#include <assert.h>
39#include <stdlib.h>
40#include <time.h>
41
42#include <avahi-core/core.h>
43#include <avahi-core/lookup.h>
44#include <avahi-common/simple-watch.h>
45#include <avahi-common/malloc.h>
46#include <avahi-common/error.h>
47
48static AvahiSimplePoll *simple_poll = NULL;
49static AvahiServer *server = NULL;
50
51static void resolve_callback(
52    AvahiSServiceResolver *r,
53    AVAHI_GCC_UNUSED AvahiIfIndex interface,
54    AVAHI_GCC_UNUSED AvahiProtocol protocol,
55    AvahiResolverEvent event,
56    const char *name,
57    const char *type,
58    const char *domain,
59    const char *host_name,
60    const AvahiAddress *address,
61    uint16_t port,
62    AvahiStringList *txt,
63    AvahiLookupResultFlags flags,
64    AVAHI_GCC_UNUSED void* userdata) {
65
66    assert(r);
67
68    /* Called whenever a service has been resolved successfully or timed out */
69
70    switch (event) {
71        case AVAHI_RESOLVER_FAILURE:
72            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)));
73            break;
74
75        case AVAHI_RESOLVER_FOUND: {
76            char a[AVAHI_ADDRESS_STR_MAX], *t;
77
78            fprintf(stderr, "(Resolver) Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
79
80            avahi_address_snprint(a, sizeof(a), address);
81            t = avahi_string_list_to_string(txt);
82            fprintf(stderr,
83                    "\t%s:%u (%s)\n"
84                    "\tTXT=%s\n"
85                    "\tcookie is %u\n"
86                    "\tis_local: %i\n"
87                    "\twide_area: %i\n"
88                    "\tmulticast: %i\n"
89                    "\tcached: %i\n",
90                    host_name, port, a,
91                    t,
92                    avahi_string_list_get_service_cookie(txt),
93                    !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
94                    !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
95                    !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
96                    !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
97            avahi_free(t);
98        }
99    }
100
101    avahi_s_service_resolver_free(r);
102}
103
104static void browse_callback(
105    AvahiSServiceBrowser *b,
106    AvahiIfIndex interface,
107    AvahiProtocol protocol,
108    AvahiBrowserEvent event,
109    const char *name,
110    const char *type,
111    const char *domain,
112    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
113    void* userdata) {
114
115    AvahiServer *s = userdata;
116    assert(b);
117
118    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
119
120    switch (event) {
121
122        case AVAHI_BROWSER_FAILURE:
123
124            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_server_errno(server)));
125            avahi_simple_poll_quit(simple_poll);
126            return;
127
128        case AVAHI_BROWSER_NEW:
129            fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
130
131            /* We ignore the returned resolver object. In the callback
132               function we free it. If the server is terminated before
133               the callback function is called the server will free
134               the resolver for us. */
135
136            if (!(avahi_s_service_resolver_new(s, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, s)))
137                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_server_errno(s)));
138
139            break;
140
141        case AVAHI_BROWSER_REMOVE:
142            fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
143            break;
144
145        case AVAHI_BROWSER_ALL_FOR_NOW:
146        case AVAHI_BROWSER_CACHE_EXHAUSTED:
147            fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
148            break;
149    }
150}
151
152int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
153    AvahiServerConfig config;
154    AvahiSServiceBrowser *sb = NULL;
155    int error;
156    int ret = 1;
157
158    /* Initialize the psuedo-RNG */
159    srand(time(NULL));
160
161    /* Allocate main loop object */
162    if (!(simple_poll = avahi_simple_poll_new())) {
163        fprintf(stderr, "Failed to create simple poll object.\n");
164        goto fail;
165    }
166
167    /* Do not publish any local records */
168    avahi_server_config_init(&config);
169    config.publish_hinfo = 0;
170    config.publish_addresses = 0;
171    config.publish_workstation = 0;
172    config.publish_domain = 0;
173
174    /* Set a unicast DNS server for wide area DNS-SD */
175    avahi_address_parse("192.168.50.1", AVAHI_PROTO_UNSPEC, &config.wide_area_servers[0]);
176    config.n_wide_area_servers = 1;
177    config.enable_wide_area = 1;
178
179    /* Allocate a new server */
180    server = avahi_server_new(avahi_simple_poll_get(simple_poll), &config, NULL, NULL, &error);
181
182    /* Free the configuration data */
183    avahi_server_config_free(&config);
184
185    /* Check wether creating the server object succeeded */
186    if (!server) {
187        fprintf(stderr, "Failed to create server: %s\n", avahi_strerror(error));
188        goto fail;
189    }
190
191    /* Create the service browser */
192    if (!(sb = avahi_s_service_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_http._tcp", NULL, 0, browse_callback, server))) {
193        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_server_errno(server)));
194        goto fail;
195    }
196
197    /* Run the main loop */
198    avahi_simple_poll_loop(simple_poll);
199
200    ret = 0;
201
202fail:
203
204    /* Cleanup things */
205    if (sb)
206        avahi_s_service_browser_free(sb);
207
208    if (server)
209        avahi_server_free(server);
210
211    if (simple_poll)
212        avahi_simple_poll_free(simple_poll);
213
214    return ret;
215}
216