• Home
  • History
  • Annotate
  • Line#
  • Navigate
  • Raw
  • Download
  • only in /netgear-R7000-V1.0.7.12_1.2.5/ap/gpl/timemachine/avahi-0.6.25/avahi-discover-standalone/
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 <sys/ioctl.h>
27#include <string.h>
28#include <sys/types.h>
29#include <sys/socket.h>
30#include <net/if.h>
31#include <unistd.h>
32
33#include <gtk/gtk.h>
34#include <glade/glade.h>
35
36#include <avahi-core/core.h>
37#include <avahi-core/lookup.h>
38
39#include <avahi-common/strlst.h>
40#include <avahi-common/domain.h>
41#include <avahi-common/error.h>
42
43#include <avahi-glib/glib-watch.h>
44#include <avahi-glib/glib-malloc.h>
45
46struct ServiceType;
47
48struct Service {
49    struct ServiceType *service_type;
50    gchar *service_name;
51    gchar *domain_name;
52
53    AvahiIfIndex interface;
54    AvahiProtocol protocol;
55
56    GtkTreeRowReference *tree_ref;
57};
58
59struct ServiceType {
60    gchar *service_type;
61    AvahiSServiceBrowser *browser;
62
63    GList *services;
64    GtkTreeRowReference *tree_ref;
65};
66
67static GtkWidget *main_window = NULL;
68static GtkTreeView *tree_view = NULL;
69static GtkTreeStore *tree_store = NULL;
70static GtkLabel *info_label = NULL;
71static AvahiServer *server = NULL;
72static AvahiSServiceTypeBrowser *service_type_browser = NULL;
73static GHashTable *service_type_hash_table = NULL;
74static AvahiSServiceResolver *service_resolver = NULL;
75static struct Service *current_service = NULL;
76
77static struct Service *get_service(const gchar *service_type, const gchar *service_name, const gchar*domain_name, AvahiIfIndex interface, AvahiProtocol protocol) {
78    struct ServiceType *st;
79    GList *l;
80
81    if (!(st = g_hash_table_lookup(service_type_hash_table, service_type)))
82        return NULL;
83
84    for (l = st->services; l; l = l->next) {
85        struct Service *s = l->data;
86
87        if (s->interface == interface &&
88            s->protocol == protocol &&
89            avahi_domain_equal(s->service_name, service_name) &&
90            avahi_domain_equal(s->domain_name, domain_name))
91            return s;
92    }
93
94    return NULL;
95}
96
97static void free_service(struct Service *s) {
98    GtkTreeIter iter;
99    GtkTreePath *path;
100
101    if (current_service == s) {
102        current_service = NULL;
103
104        if (service_resolver) {
105            avahi_s_service_resolver_free(service_resolver);
106            service_resolver = NULL;
107        }
108
109        gtk_label_set_text(info_label, "<i>Service removed</i>");
110    }
111
112    s->service_type->services = g_list_remove(s->service_type->services, s);
113
114    if ((path = gtk_tree_row_reference_get_path(s->tree_ref))) {
115        gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store), &iter, path);
116        gtk_tree_path_free(path);
117    }
118
119    gtk_tree_store_remove(tree_store, &iter);
120
121    gtk_tree_row_reference_free(s->tree_ref);
122
123    g_free(s->service_name);
124    g_free(s->domain_name);
125    g_free(s);
126}
127
128static void service_browser_callback(
129    AVAHI_GCC_UNUSED AvahiSServiceBrowser *b,
130    AvahiIfIndex interface,
131    AvahiProtocol protocol,
132    AvahiBrowserEvent event,
133    const char *service_name,
134    const char *service_type,
135    const char *domain_name,
136    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
137    AVAHI_GCC_UNUSED void* userdata) {
138
139    if (event == AVAHI_BROWSER_NEW) {
140        struct Service *s;
141        GtkTreeIter iter, piter;
142        GtkTreePath *path, *ppath;
143        gchar iface[256];
144	char name[IF_NAMESIZE];
145
146        s = g_new(struct Service, 1);
147        s->service_name = g_strdup(service_name);
148        s->domain_name = g_strdup(domain_name);
149        s->interface = interface;
150        s->protocol = protocol;
151        s->service_type = g_hash_table_lookup(service_type_hash_table, service_type);
152        g_assert(s->service_type);
153
154        s->service_type->services = g_list_prepend(s->service_type->services, s);
155
156        ppath = gtk_tree_row_reference_get_path(s->service_type->tree_ref);
157        gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store), &piter, ppath);
158
159        snprintf(iface, sizeof(iface), "%s %s", if_indextoname(interface, name), avahi_proto_to_string(protocol));
160
161        gtk_tree_store_append(tree_store, &iter, &piter);
162        gtk_tree_store_set(tree_store, &iter, 0, s->service_name, 1, iface, 2, s, -1);
163
164        path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store), &iter);
165        s->tree_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(tree_store), path);
166        gtk_tree_path_free(path);
167
168        gtk_tree_view_expand_row(tree_view, ppath, FALSE);
169        gtk_tree_path_free(ppath);
170
171
172    } else if (event == AVAHI_BROWSER_REMOVE) {
173        struct Service* s;
174
175        if ((s = get_service(service_type, service_name, domain_name, interface, protocol)))
176            free_service(s);
177    }
178}
179
180static void service_type_browser_callback(
181    AVAHI_GCC_UNUSED AvahiSServiceTypeBrowser *b,
182    AVAHI_GCC_UNUSED AvahiIfIndex interface,
183    AVAHI_GCC_UNUSED AvahiProtocol protocol,
184    AvahiBrowserEvent event,
185    const char *service_type,
186    const char *domain,
187    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
188    AVAHI_GCC_UNUSED void * userdata) {
189
190    struct ServiceType *st;
191    GtkTreePath *path;
192    GtkTreeIter iter;
193
194    if (event != AVAHI_BROWSER_NEW)
195        return;
196
197    if (g_hash_table_lookup(service_type_hash_table, service_type))
198        return;
199
200    st = g_new(struct ServiceType, 1);
201    st->service_type = g_strdup(service_type);
202    st->services = NULL;
203
204    gtk_tree_store_append(tree_store, &iter, NULL);
205    gtk_tree_store_set(tree_store, &iter, 0, st->service_type, 1, "", 2, NULL, -1);
206
207    path = gtk_tree_model_get_path(GTK_TREE_MODEL(tree_store), &iter);
208    st->tree_ref = gtk_tree_row_reference_new(GTK_TREE_MODEL(tree_store), path);
209    gtk_tree_path_free(path);
210
211    g_hash_table_insert(service_type_hash_table, st->service_type, st);
212
213    st->browser = avahi_s_service_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, st->service_type, domain, 0, service_browser_callback, NULL);
214}
215
216static void update_label(struct Service *s, const gchar *hostname, const AvahiAddress *a, guint16 port, AvahiStringList *txt) {
217    gchar t[512], address[64], *txt_s;
218    char name[IF_NAMESIZE];
219
220    if (a && hostname) {
221        char na[AVAHI_ADDRESS_STR_MAX];
222        avahi_address_snprint(na, sizeof(na), a);
223        snprintf(address, sizeof(address), "%s/%s:%u", hostname, na, port);
224
225        if (txt)
226            txt_s = avahi_string_list_to_string(txt);
227        else
228            txt_s = g_strdup("<i>empty</i>");
229    } else {
230        snprintf(address, sizeof(address), "<i>n/a</i>");
231        txt_s = g_strdup("<i>n/a</i>");
232    }
233
234    snprintf(t, sizeof(t),
235             "<b>Service Type:</b> %s\n"
236             "<b>Service Name:</b> %s\n"
237             "<b>Domain Name:</b> %s\n"
238             "<b>Interface:</b> %s %s\n"
239             "<b>Address:</b> %s\n"
240             "<b>TXT Data:</b> %s",
241             s->service_type->service_type,
242             s->service_name,
243             s->domain_name,
244             if_indextoname(s->interface,name), avahi_proto_to_string(s->protocol),
245             address,
246             txt_s);
247
248    gtk_label_set_markup(info_label, t);
249
250    g_free(txt_s);
251}
252
253static struct Service *get_service_on_cursor(void) {
254    GtkTreePath *path;
255    struct Service *s;
256    GtkTreeIter iter;
257
258    gtk_tree_view_get_cursor(tree_view, &path, NULL);
259
260    if (!path)
261        return NULL;
262
263    gtk_tree_model_get_iter(GTK_TREE_MODEL(tree_store), &iter, path);
264    gtk_tree_model_get(GTK_TREE_MODEL(tree_store), &iter, 2, &s, -1);
265    gtk_tree_path_free(path);
266
267    return s;
268}
269
270static void service_resolver_callback(
271    AvahiSServiceResolver *r,
272    AVAHI_GCC_UNUSED AvahiIfIndex interface,
273    AVAHI_GCC_UNUSED AvahiProtocol protocol,
274    AvahiResolverEvent event,
275    AVAHI_GCC_UNUSED const char *name,
276    AVAHI_GCC_UNUSED const char *type,
277    AVAHI_GCC_UNUSED const char *domain,
278    const char *host_name,
279    const AvahiAddress *a,
280    uint16_t port,
281    AvahiStringList *txt,
282    AVAHI_GCC_UNUSED AvahiLookupResultFlags flags,
283    void* userdata) {
284
285    struct Service *s;
286    g_assert(r);
287
288    if (!(s = get_service_on_cursor()) || userdata != s) {
289        g_assert(r == service_resolver);
290        avahi_s_service_resolver_free(service_resolver);
291        service_resolver = NULL;
292        return;
293    }
294
295    if (event == AVAHI_RESOLVER_FAILURE) {
296        char t[256];
297        snprintf(t, sizeof(t), "<i>Failed to resolve: %s.</i>", avahi_strerror(avahi_server_errno(server)));
298        gtk_label_set_markup(info_label, t);
299    } else if (event == AVAHI_RESOLVER_FOUND)
300        update_label(s, host_name, a, port, txt);
301}
302
303static void tree_view_on_cursor_changed(AVAHI_GCC_UNUSED GtkTreeView *tv, AVAHI_GCC_UNUSED gpointer userdata) {
304    struct Service *s;
305
306    if (!(s = get_service_on_cursor()))
307        return;
308
309    if (service_resolver)
310        avahi_s_service_resolver_free(service_resolver);
311
312    update_label(s, NULL, NULL, 0, NULL);
313
314    service_resolver = avahi_s_service_resolver_new(server, s->interface, s->protocol, s->service_name, s->service_type->service_type, s->domain_name, AVAHI_PROTO_UNSPEC, 0, service_resolver_callback, s);
315}
316
317static gboolean main_window_on_delete_event(AVAHI_GCC_UNUSED GtkWidget *widget, AVAHI_GCC_UNUSED GdkEvent *event, AVAHI_GCC_UNUSED gpointer user_data) {
318    gtk_main_quit();
319    return FALSE;
320}
321
322int main(int argc, char *argv[]) {
323    GladeXML *xml;
324    AvahiServerConfig config;
325    GtkTreeViewColumn *c;
326    gint error;
327    AvahiGLibPoll *poll_api;
328
329    gtk_init(&argc, &argv);
330    glade_init();
331
332    avahi_set_allocator(avahi_glib_allocator());
333
334    poll_api = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
335
336    xml = glade_xml_new(AVAHI_INTERFACES_DIR"avahi-discover.glade", NULL, NULL);
337    main_window = glade_xml_get_widget(xml, "main_window");
338    g_signal_connect(main_window, "delete-event", (GCallback) main_window_on_delete_event, NULL);
339
340    tree_view = GTK_TREE_VIEW(glade_xml_get_widget(xml, "tree_view"));
341    g_signal_connect(GTK_WIDGET(tree_view), "cursor-changed", (GCallback) tree_view_on_cursor_changed, NULL);
342
343    info_label = GTK_LABEL(glade_xml_get_widget(xml, "info_label"));
344
345    tree_store = gtk_tree_store_new(3, G_TYPE_STRING, G_TYPE_STRING, G_TYPE_POINTER);
346    gtk_tree_view_set_model(tree_view, GTK_TREE_MODEL(tree_store));
347    gtk_tree_view_insert_column_with_attributes(tree_view, -1, "Name", gtk_cell_renderer_text_new(), "text", 0, NULL);
348    gtk_tree_view_insert_column_with_attributes(tree_view, -1, "Interface", gtk_cell_renderer_text_new(), "text", 1, NULL);
349
350    gtk_tree_view_column_set_resizable(c = gtk_tree_view_get_column(tree_view, 0), TRUE);
351    gtk_tree_view_column_set_sizing(c, GTK_TREE_VIEW_COLUMN_GROW_ONLY);
352    gtk_tree_view_column_set_expand(c, TRUE);
353
354    service_type_hash_table = g_hash_table_new((GHashFunc) avahi_domain_hash, (GEqualFunc) avahi_domain_equal);
355
356    avahi_server_config_init(&config);
357    config.publish_hinfo = config.publish_addresses = config.publish_domain = config.publish_workstation = FALSE;
358    server = avahi_server_new(avahi_glib_poll_get(poll_api), &config, NULL, NULL, &error);
359    avahi_server_config_free(&config);
360
361    g_assert(server);
362
363    service_type_browser = avahi_s_service_type_browser_new(server, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, argc >= 2 ? argv[1] : NULL, 0, service_type_browser_callback, NULL);
364
365    gtk_main();
366
367    avahi_server_free(server);
368    avahi_glib_poll_free(poll_api);
369
370    return 0;
371}
372