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 <stdio.h>
27#include <assert.h>
28#include <stdlib.h>
29#include <time.h>
30
31#include <avahi-client/client.h>
32#include <avahi-client/lookup.h>
33
34#include <avahi-common/simple-watch.h>
35#include <avahi-common/malloc.h>
36#include <avahi-common/error.h>
37
38static AvahiSimplePoll *simple_poll = NULL;
39
40static void resolve_callback(
41    AvahiServiceResolver *r,
42    AVAHI_GCC_UNUSED AvahiIfIndex interface,
43    AVAHI_GCC_UNUSED AvahiProtocol protocol,
44    AvahiResolverEvent event,
45    const char *name,
46    const char *type,
47    const char *domain,
48    const char *host_name,
49    const AvahiAddress *address,
50    uint16_t port,
51    AvahiStringList *txt,
52    AvahiLookupResultFlags flags,
53    AVAHI_GCC_UNUSED void* userdata) {
54
55    assert(r);
56
57    /* Called whenever a service has been resolved successfully or timed out */
58
59    switch (event) {
60        case AVAHI_RESOLVER_FAILURE:
61            fprintf(stderr, "(Resolver) Failed to resolve service '%s' of type '%s' in domain '%s': %s\n", name, type, domain, avahi_strerror(avahi_client_errno(avahi_service_resolver_get_client(r))));
62            break;
63
64        case AVAHI_RESOLVER_FOUND: {
65            char a[AVAHI_ADDRESS_STR_MAX], *t;
66
67            fprintf(stderr, "Service '%s' of type '%s' in domain '%s':\n", name, type, domain);
68
69            avahi_address_snprint(a, sizeof(a), address);
70            t = avahi_string_list_to_string(txt);
71            fprintf(stderr,
72                    "\t%s:%u (%s)\n"
73                    "\tTXT=%s\n"
74                    "\tcookie is %u\n"
75                    "\tis_local: %i\n"
76                    "\tour_own: %i\n"
77                    "\twide_area: %i\n"
78                    "\tmulticast: %i\n"
79                    "\tcached: %i\n",
80                    host_name, port, a,
81                    t,
82                    avahi_string_list_get_service_cookie(txt),
83                    !!(flags & AVAHI_LOOKUP_RESULT_LOCAL),
84                    !!(flags & AVAHI_LOOKUP_RESULT_OUR_OWN),
85                    !!(flags & AVAHI_LOOKUP_RESULT_WIDE_AREA),
86                    !!(flags & AVAHI_LOOKUP_RESULT_MULTICAST),
87                    !!(flags & AVAHI_LOOKUP_RESULT_CACHED));
88
89            avahi_free(t);
90        }
91    }
92
93    avahi_service_resolver_free(r);
94}
95
96static void browse_callback(
97    AvahiServiceBrowser *b,
98    AvahiIfIndex interface,
99    AvahiProtocol protocol,
100    AvahiBrowserEvent event,
101    const char *name,
102    const char *type,
103    const char *domain,
104    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
105    void* userdata) {
106
107    AvahiClient *c = userdata;
108    assert(b);
109
110    /* Called whenever a new services becomes available on the LAN or is removed from the LAN */
111
112    switch (event) {
113        case AVAHI_BROWSER_FAILURE:
114
115            fprintf(stderr, "(Browser) %s\n", avahi_strerror(avahi_client_errno(avahi_service_browser_get_client(b))));
116            avahi_simple_poll_quit(simple_poll);
117            return;
118
119        case AVAHI_BROWSER_NEW:
120            fprintf(stderr, "(Browser) NEW: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
121
122            /* We ignore the returned resolver object. In the callback
123               function we free it. If the server is terminated before
124               the callback function is called the server will free
125               the resolver for us. */
126
127            if (!(avahi_service_resolver_new(c, interface, protocol, name, type, domain, AVAHI_PROTO_UNSPEC, 0, resolve_callback, c)))
128                fprintf(stderr, "Failed to resolve service '%s': %s\n", name, avahi_strerror(avahi_client_errno(c)));
129
130            break;
131
132        case AVAHI_BROWSER_REMOVE:
133            fprintf(stderr, "(Browser) REMOVE: service '%s' of type '%s' in domain '%s'\n", name, type, domain);
134            break;
135
136        case AVAHI_BROWSER_ALL_FOR_NOW:
137        case AVAHI_BROWSER_CACHE_EXHAUSTED:
138            fprintf(stderr, "(Browser) %s\n", event == AVAHI_BROWSER_CACHE_EXHAUSTED ? "CACHE_EXHAUSTED" : "ALL_FOR_NOW");
139            break;
140    }
141}
142
143static void client_callback(AvahiClient *c, AvahiClientState state, AVAHI_GCC_UNUSED void * userdata) {
144    assert(c);
145
146    /* Called whenever the client or server state changes */
147
148    if (state == AVAHI_CLIENT_FAILURE) {
149        fprintf(stderr, "Server connection failure: %s\n", avahi_strerror(avahi_client_errno(c)));
150        avahi_simple_poll_quit(simple_poll);
151    }
152}
153
154int main(AVAHI_GCC_UNUSED int argc, AVAHI_GCC_UNUSED char*argv[]) {
155    AvahiClient *client = NULL;
156    AvahiServiceBrowser *sb = NULL;
157    int error;
158    int ret = 1;
159
160    /* Allocate main loop object */
161    if (!(simple_poll = avahi_simple_poll_new())) {
162        fprintf(stderr, "Failed to create simple poll object.\n");
163        goto fail;
164    }
165
166    /* Allocate a new client */
167    client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0, client_callback, NULL, &error);
168
169    /* Check wether creating the client object succeeded */
170    if (!client) {
171        fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
172        goto fail;
173    }
174
175    /* Create the service browser */
176    if (!(sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, "_http._tcp", NULL, 0, browse_callback, client))) {
177        fprintf(stderr, "Failed to create service browser: %s\n", avahi_strerror(avahi_client_errno(client)));
178        goto fail;
179    }
180
181    /* Run the main loop */
182    avahi_simple_poll_loop(simple_poll);
183
184    ret = 0;
185
186fail:
187
188    /* Cleanup things */
189    if (sb)
190        avahi_service_browser_free(sb);
191
192    if (client)
193        avahi_client_free(client);
194
195    if (simple_poll)
196        avahi_simple_poll_free(simple_poll);
197
198    return ret;
199}
200