aboutsummaryrefslogtreecommitdiffstats
diff options
context:
space:
mode:
-rw-r--r--.cvsignore2
-rw-r--r--GNUmakefile41
-rw-r--r--mdns-browser.c81
-rw-r--r--mdns-publish-xendom.c180
-rw-r--r--mdns.c655
-rw-r--r--mdns.h11
-rw-r--r--xd_view.c35
-rw-r--r--xenwatch.c7
8 files changed, 909 insertions, 103 deletions
diff --git a/.cvsignore b/.cvsignore
index e93e41a..273c710 100644
--- a/.cvsignore
+++ b/.cvsignore
@@ -1,3 +1,5 @@
Make.config
xenlog
xenwatch
+mdns-browser
+mdns-publish-xendom
diff --git a/GNUmakefile b/GNUmakefile
index 5289274..57fa683 100644
--- a/GNUmakefile
+++ b/GNUmakefile
@@ -7,7 +7,12 @@ CFLAGS += -DVERSION='"$(VERSION)"'
# build
TARGETS := xenlog
-GTK_TARGETS := xenwatch
+BUILD_GTK := xenwatch mdns-browser
+BUILD_MDNS := mdns-publish-xendom
+
+NEEDS_XENSTORE := xenlog xenwatch mdns-publish-xendom
+NEEDS_GTK := xenwatch mdns-browser
+NEEDS_MDNS := xenwatch mdns-browser mdns-publish-xendom
# default target
all: build
@@ -26,22 +31,29 @@ endef
# gtk stuff
ifeq ($(HAVE_GTK),yes)
- pkgs := gtk+-x11-2.0
- ifeq ($(HAVE_AVAHI),yes)
- CFLAGS += -DHAVE_AVAHI=1
- pkgs += avahi-glib avahi-client
- endif
- $(GTK_TARGETS) : CFLAGS += $(shell pkg-config --cflags $(pkgs)) -Wno-strict-prototypes
- $(GTK_TARGETS) : LDLIBS += $(shell pkg-config --libs $(pkgs))
- TARGETS += $(GTK_TARGETS)
+ $(NEEDS_GTK) : CFLAGS += -Wno-strict-prototypes
+ $(NEEDS_GTK) : pkglst += gtk+-x11-2.0
+ TARGETS += $(BUILD_GTK)
+endif
+
+# avahi stuff
+ifeq ($(HAVE_AVAHI),yes)
+ $(NEEDS_MDNS) : CFLAGS += -DHAVE_AVAHI=1
+ $(NEEDS_MDNS) : pkglst += avahi-client
+ $(NEEDS_GTK) : pkglst += avahi-glib
+ TARGETS += $(BUILD_MDNS)
endif
+# pkg-config flags
+CFLAGS += $(shell test "$(pkglst)" != "" && pkg-config --cflags $(pkglst))
+LDLIBS += $(shell test "$(pkglst)" != "" && pkg-config --libs $(pkglst))
+
# xenstore
ifneq ($(XENSRC),)
- CFLAGS += -I $(XENSRC)/dist/install/usr/include
- LDLIBS += -I $(XENSRC)/dist/install/usr/$(LIB)
+ $(NEEDS_XENSTORE) : CFLAGS += -I $(XENSRC)/dist/install/usr/include
+ $(NEEDS_XENSTORE) : LDLIBS += -I $(XENSRC)/dist/install/usr/$(LIB)
endif
-LDLIBS += -lxenstore
+$(NEEDS_XENSTORE) : LDLIBS += -lxenstore
########################################################################
@@ -62,9 +74,10 @@ realclean distclean: clean
#############################################
-xenwatch: xenwatch.o xs_view.o xs_store.o xd_view.o xd_store.o tcp.o mdns.o
-
xenlog: xenlog.o
+xenwatch: xenwatch.o xs_view.o xs_store.o xd_view.o xd_store.o tcp.o mdns.o
+mdns-browser: mdns-browser.o mdns.o
+mdns-publish-xendom: mdns-publish-xendom.o
include mk/Compile.mk
include mk/Maintainer.mk
diff --git a/mdns-browser.c b/mdns-browser.c
new file mode 100644
index 0000000..9f004b7
--- /dev/null
+++ b/mdns-browser.c
@@ -0,0 +1,81 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <unistd.h>
+#include <string.h>
+#include <errno.h>
+#include <fcntl.h>
+#include <locale.h>
+#include <signal.h>
+
+#include <gdk/gdk.h>
+#include <gdk/gdkx.h>
+#include <gtk/gtk.h>
+
+#include "mdns.h"
+
+/* ------------------------------------------------------------------ */
+
+static Display *dpy;
+static struct mdns_window *mdns;
+
+static char *service = "_ssh._tcp";
+static char *domain = NULL;
+
+/* ------------------------------------------------------------------ */
+
+static void usage(FILE *fp)
+{
+ fprintf(fp,
+ "This is a mDNS browser\n"
+ "\n"
+ "usage: mdns-browser [options]\n"
+ "options:\n"
+ " -h print this text\n"
+ " -s <service> specify service [%s]\n"
+ " -d <domain> specify domain\n"
+ "\n"
+ "-- \n"
+ "(c) 2006 Gerd Hoffmann <kraxel@suse.de>\n",
+ service);
+}
+
+int
+main(int argc, char *argv[])
+{
+ int c;
+
+ gtk_init(&argc, &argv);
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "hs:d:")))
+ break;
+ switch (c) {
+ case 's':
+ service = optarg;
+ break;
+ case 'd':
+ domain = optarg;
+ break;
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
+ fcntl(ConnectionNumber(dpy),F_SETFD,FD_CLOEXEC);
+
+ mdns = mdns_create_window(1);
+ if (NULL == mdns) {
+ fprintf(stderr,"Oops: mDNS did't initialize ok\n");
+ exit(1);
+ }
+ mdns_show_window(mdns);
+ mdns_browse(mdns, service, domain);
+
+ gtk_main();
+ fprintf(stderr,"bye...\n");
+ exit(0);
+}
diff --git a/mdns-publish-xendom.c b/mdns-publish-xendom.c
new file mode 100644
index 0000000..3d69ab6
--- /dev/null
+++ b/mdns-publish-xendom.c
@@ -0,0 +1,180 @@
+#include <time.h>
+#include <stdio.h>
+#include <stdlib.h>
+#include <sys/utsname.h>
+
+#include <xs.h>
+
+#include <avahi-client/client.h>
+#include <avahi-client/publish.h>
+
+#include <avahi-common/alternative.h>
+#include <avahi-common/simple-watch.h>
+#include <avahi-common/malloc.h>
+#include <avahi-common/error.h>
+
+static AvahiEntryGroup *group = NULL;
+static AvahiSimplePoll *simple_poll = NULL;
+
+static char *name;
+static char *service = "_xendom._tcp";
+static int port = 9;
+
+static void create_services(AvahiClient *c);
+
+static void entry_group_callback(AvahiEntryGroup *g,
+ AvahiEntryGroupState state,
+ void *userdata)
+{
+ char *n;
+
+ switch (state) {
+ case AVAHI_ENTRY_GROUP_ESTABLISHED:
+ fprintf(stderr, "Service '%s' successfully established.\n", name);
+ break;
+ case AVAHI_ENTRY_GROUP_COLLISION:
+ n = avahi_alternative_service_name(name);
+ avahi_free(name);
+ name = n;
+ fprintf(stderr, "Service name collision, renaming service to '%s'\n", name);
+ create_services(avahi_entry_group_get_client(g));
+ break;
+ case AVAHI_ENTRY_GROUP_FAILURE :
+ avahi_simple_poll_quit(simple_poll);
+ break;
+ default:
+ break;
+ }
+}
+
+static void create_services(AvahiClient *c)
+{
+ char r[128];
+ int ret;
+
+ /* If this is the first time we're called, let's create a new entry group */
+ if (!group) {
+ if (!(group = avahi_entry_group_new(c, entry_group_callback, NULL))) {
+ fprintf(stderr, "avahi_entry_group_new() failed: %s\n",
+ avahi_strerror(avahi_client_errno(c)));
+ goto fail;
+ }
+ }
+
+ fprintf(stderr, "Adding service '%s'\n", name);
+
+ /* Create some random TXT data */
+ snprintf(r, sizeof(r), "random=%i", rand());
+
+ /* Add the service for IPP */
+ ret = avahi_entry_group_add_service(group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0,
+ name, service, NULL, NULL, port,
+ "test=blah", r, NULL);
+ if (ret < 0) {
+ fprintf(stderr, "Failed to add %s service: %s\n", service, avahi_strerror(ret));
+ goto fail;
+ }
+
+ /* Tell the server to register the service */
+ if ((ret = avahi_entry_group_commit(group)) < 0) {
+ fprintf(stderr, "Failed to commit entry_group: %s\n", avahi_strerror(ret));
+ goto fail;
+ }
+ return;
+
+fail:
+ avahi_simple_poll_quit(simple_poll);
+}
+
+static void client_callback(AvahiClient *c,
+ AvahiClientState state,
+ void * userdata)
+{
+ switch (state) {
+ case AVAHI_CLIENT_S_RUNNING:
+ if (!group)
+ create_services(c);
+ break;
+ case AVAHI_CLIENT_S_COLLISION:
+ if (group)
+ avahi_entry_group_reset(group);
+ break;
+ case AVAHI_CLIENT_FAILURE:
+ fprintf(stderr, "Client failure: %s\n", avahi_strerror(avahi_client_errno(c)));
+ avahi_simple_poll_quit(simple_poll);
+ break;
+ default:
+ break;
+ }
+}
+
+static void xendom_info(void)
+{
+ struct xs_handle *xenstore;
+ struct xs_transaction_handle *xst;
+ char *xs_value;
+
+ xenstore = xs_domain_open();
+ if (NULL == xenstore) {
+ fprintf(stderr,"%s: can't connect to %s\n", __FUNCTION__,
+ xs_domain_dev());
+ return;
+ }
+
+ if (NULL == (xst = xs_transaction_start(xenstore)))
+ goto out;
+ xs_value = xs_read(xenstore, xst, "vm", NULL);
+ xs_transaction_end(xenstore, xst, 0);
+ if (!xs_value)
+ goto out;
+
+ fprintf(stderr, "%s", xs_value);
+
+ out:
+ return;
+}
+
+int main(int argc, char*argv[])
+{
+ AvahiClient *client = NULL;
+ char buf[128];
+ struct utsname uts;
+ int error;
+ int ret = 1;
+
+ /* figure name */
+ uname(&uts);
+ snprintf(buf, sizeof(buf), "Xen domain %s", uts.nodename);
+ name = avahi_strdup(buf);
+
+ /* figure domain info */
+ xendom_info();
+
+ /* go announce info */
+ simple_poll = avahi_simple_poll_new();
+ if (!simple_poll) {
+ fprintf(stderr, "Failed to create simple poll object.\n");
+ goto fail;
+ }
+
+ client = avahi_client_new(avahi_simple_poll_get(simple_poll), 0,
+ client_callback, NULL, &error);
+ if (!client) {
+ fprintf(stderr, "Failed to create client: %s\n", avahi_strerror(error));
+ goto fail;
+ }
+
+ avahi_simple_poll_loop(simple_poll);
+ ret = 0;
+
+fail:
+ /* Cleanup things */
+ if (client)
+ avahi_client_free(client);
+
+ if (simple_poll)
+ avahi_simple_poll_free(simple_poll);
+
+ avahi_free(name);
+ return ret;
+}
diff --git a/mdns.c b/mdns.c
index 9e27006..ec7d29f 100644
--- a/mdns.c
+++ b/mdns.c
@@ -3,8 +3,15 @@
#include <unistd.h>
#include <string.h>
+#include <sys/ioctl.h>
+#include <sys/types.h>
+#include <sys/socket.h>
+#include <linux/if.h> /* FIXME: find more portable one */
+
+#include <glib.h>
+#include <gtk/gtk.h>
+
#ifdef HAVE_AVAHI
-# include <glib.h>
# include <avahi-client/client.h>
# include <avahi-client/lookup.h>
# include <avahi-common/error.h>
@@ -18,6 +25,41 @@
#ifdef HAVE_AVAHI
+static int debug = 0;
+
+/* ---------------------------------------------------------------------- */
+
+enum {
+ /* browse */
+ ST_COL_NAME = 0,
+ ST_COL_TYPE,
+ ST_COL_DOMAIN,
+ ST_COL_INTERFACE,
+ ST_COL_PROTOCOL,
+
+ /* resolve */
+ ST_COL_HOSTNAME,
+ ST_COL_ADDR,
+ ST_COL_PORT,
+ ST_COL_PATH,
+
+ /* other */
+ ST_COL_URL,
+
+ ST_NUM_COLS
+};
+
+struct mdns_window {
+ GtkListStore *store;
+ GtkWidget *toplevel, *view, *status;
+ int standalone;
+
+ const AvahiPoll *poll_api;
+ AvahiGLibPoll *glib_poll;
+ AvahiClient *client;
+ AvahiServiceBrowser *sb;
+};
+
/* ---------------------------------------------------------------------- */
static const char *revents[] = {
@@ -32,27 +74,108 @@ static const char *bevents[] = {
[ AVAHI_BROWSER_FAILURE ] = "FAILURE",
};
-static const AvahiPoll *poll_api;
-static AvahiGLibPoll *glib_poll;
-static AvahiClient *client;
-
-struct mdns_entry {
- const char *name;
- const char *type;
- const char *domain;
- AvahiIfIndex interface;
- AvahiProtocol protocol;
-
- const char *address;
- const char *hostname;
- uint16_t port;
-
- struct list_head next;
-};
-static LIST_HEAD(mdns_entries);
+/* ---------------------------------------------------------------------- */
+
+static int find_entry(struct mdns_window *mdns, GtkTreeIter *iter,
+ const char *sname, const char *stype, const char *sdomain,
+ const char *sproto, const char *snif)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL(mdns->store);
+ gboolean valid;
+ char *name, *type, *domain, *proto, *nif;
+
+ for (valid = gtk_tree_model_get_iter_first(model, iter);
+ valid;
+ valid = gtk_tree_model_iter_next(model, iter))
+ {
+ gtk_tree_model_get(model, iter,
+ ST_COL_NAME, &name,
+ ST_COL_TYPE, &type,
+ ST_COL_DOMAIN, &domain,
+ ST_COL_PROTOCOL, &proto,
+ ST_COL_INTERFACE, &nif,
+ -1);
+ if (0 == strcmp(name, sname) &&
+ 0 == strcmp(type, stype) &&
+ 0 == strcmp(domain, sdomain) &&
+ 0 == strcmp(proto, sproto) &&
+ 0 == strcmp(nif, snif))
+ return 0;
+ }
+ return -1;
+}
+
+static void get_entry(struct mdns_window *mdns, GtkTreeIter *iter,
+ const char *sname, const char *stype, const char *sdomain,
+ const char *sproto, const char *snif)
+{
+ if (0 == find_entry(mdns, iter, sname, stype, sdomain, sproto, snif))
+ return;
+ gtk_list_store_append(mdns->store, iter);
+ gtk_list_store_set(mdns->store, iter,
+ ST_COL_NAME, sname,
+ ST_COL_TYPE, stype,
+ ST_COL_DOMAIN, sdomain,
+ ST_COL_PROTOCOL, sproto,
+ ST_COL_INTERFACE, snif,
+ -1);
+ if (debug)
+ fprintf(stderr, "add: %s: %s\n",stype, sname);
+}
+
+static void del_entry(struct mdns_window *mdns,
+ const char *sname, const char *stype, const char *sdomain,
+ const char *sproto, const char *snif)
+{
+ GtkTreeIter iter;
+
+ if (0 == find_entry(mdns, &iter, sname, stype, sdomain, sproto, snif))
+ return;
+ gtk_list_store_remove(mdns->store, &iter);
+ if (debug)
+ fprintf(stderr, "del: %s: %s\n", stype, sname);
+}
+
+static void del_entries(struct mdns_window *mdns)
+{
+ GtkTreeModel *model = GTK_TREE_MODEL(mdns->store);
+ GtkTreeIter iter;
+
+ while (gtk_tree_model_get_iter_first(model, &iter))
+ gtk_list_store_remove(mdns->store, &iter);
+}
/* ---------------------------------------------------------------------- */
+static void ifname(char *dst, int len, int nif)
+{
+#ifdef SIOCGIFNAME
+ struct ifreq ifr;
+ int fd;
+
+ fd = socket(PF_INET, SOCK_STREAM, 0);
+ if (fd < 0)
+ goto fallback;
+
+ ifr.ifr_ifindex = nif;
+ if (ioctl (fd, SIOCGIFNAME, &ifr) < 0) {
+ close (fd);
+ goto fallback;
+ }
+ snprintf(dst, len, "%s", ifr.ifr_name);
+ close (fd);
+ return;
+
+ fallback:
+#endif
+
+ if (-1 == nif) {
+ snprintf(dst, len, "wide");
+ return;
+ }
+ snprintf(dst, len, "if-%d", nif);
+}
+
static void resolve_callback(AvahiServiceResolver *r,
AvahiIfIndex interface,
AvahiProtocol protocol,
@@ -67,19 +190,66 @@ static void resolve_callback(AvahiServiceResolver *r,
AvahiLookupResultFlags flags,
void* userdata)
{
- struct mdns_entry *e = userdata;
- char a[AVAHI_ADDRESS_STR_MAX];
+ static const struct {
+ char *type;
+ char *proto;
+ int defport;
+ } protos[] = {
+ { "_http._tcp", "http", 80 },
+ { "_ftp._tcp", "ftp", 21 },
+ };
+ struct mdns_window *mdns = userdata;
+ char a[AVAHI_ADDRESS_STR_MAX], p[32], url[256];
+ unsigned char *path = NULL;
+ char *proto = NULL;
+ AvahiStringList *pathlist;
+ GtkTreeIter iter;
+ char nif[32];
+ int defport, i;
switch (event) {
case AVAHI_RESOLVER_FOUND:
+ ifname(nif, sizeof(nif), interface);
+ if (0 != find_entry(mdns, &iter, name, type, domain,
+ avahi_proto_to_string(protocol), nif))
+ break;
avahi_address_snprint(a, sizeof(a), address);
- e->address = strdup(a);
- e->hostname = strdup(host_name);
- e->port = port;
- fprintf(stderr, "%s @ %s: %s | %s if #%d | %s:%d (%s)\n",
- e->type, e->domain, e->name,
- avahi_proto_to_string(e->protocol), e->interface,
- e->address, e->port, e->hostname);
+ snprintf(p, sizeof(p), "%d", port);
+ gtk_list_store_set(mdns->store, &iter,
+ ST_COL_HOSTNAME, host_name,
+ ST_COL_ADDR, a,
+ ST_COL_PORT, p,
+ -1);
+
+ /* path */
+ pathlist = avahi_string_list_find(txt, "path");
+ if (pathlist)
+ path = avahi_string_list_get_text(pathlist);
+ if (!path)
+ break;
+ gtk_list_store_set(mdns->store, &iter,
+ ST_COL_PATH, path+5,
+ -1);
+
+ /* url */
+ for (i = 0; i < sizeof(protos)/sizeof(protos[0]); i++) {
+ if (0 != strcmp(protos[i].type, type))
+ continue;
+ proto = protos[i].proto;
+ defport = protos[i].defport;
+ break;
+ }
+ if (!proto)
+ break;
+ if (defport != port)
+ snprintf(url, sizeof(url), "%s://%s:%d%s",
+ proto, host_name, port, path+5);
+ else
+ snprintf(url, sizeof(url), "%s://%s%s",
+ proto, host_name, path+5);
+ gtk_list_store_set(mdns->store, &iter,
+ ST_COL_URL, url,
+ -1);
break;
default:
fprintf(stderr, "%s: %s (#%d)\n", __FUNCTION__,
@@ -99,29 +269,29 @@ static void browse_callback(AvahiServiceBrowser *b,
AvahiLookupResultFlags flags,
void* userdata)
{
- AvahiClient *c = userdata;
- struct mdns_entry *e;
+ struct mdns_window *mdns = userdata;
+ GtkTreeIter iter;
+ char nif[32];
+
+ ifname(nif, sizeof(nif), interface);
switch (event) {
case AVAHI_BROWSER_NEW:
- e = malloc(sizeof(*e));
- memset(e,0,sizeof(*e));
- e->name = strdup(name);
- e->type = strdup(type);
- e->domain = strdup(domain);
- e->interface = interface;
- e->protocol = protocol;
- list_add_tail(&e->next, &mdns_entries);
- avahi_service_resolver_new(c, interface, protocol, name, type, domain,
- AVAHI_PROTO_UNSPEC, 0, resolve_callback, e);
+ get_entry(mdns, &iter, name, type, domain,
+ avahi_proto_to_string(protocol), nif);
+ avahi_service_resolver_new(mdns->client,
+ interface, protocol, name, type, domain,
+ AVAHI_PROTO_UNSPEC, 0,
+ resolve_callback, mdns);
break;
case AVAHI_BROWSER_REMOVE:
- fprintf(stderr, "%s: DEL: service '%s' of type '%s' in domain '%s'\n",
- __FUNCTION__, name, type, domain);
+ del_entry(mdns, name, type, domain,
+ avahi_proto_to_string(protocol), nif);
break;
default:
- fprintf(stderr, "%s: %s (#%d)\n", __FUNCTION__,
- bevents[event], event);
+ if (debug)
+ fprintf(stderr, "%s: %s (#%d)\n", __FUNCTION__,
+ bevents[event], event);
break;
}
}
@@ -129,80 +299,419 @@ static void browse_callback(AvahiServiceBrowser *b,
static void
client_callback(AvahiClient *client, AvahiClientState state, void *userdata)
{
+// struct mdns_window *mdns = userdata;
+
switch (state) {
case AVAHI_CLIENT_FAILURE:
fprintf(stderr, "%s: error: connection lost\n", __FUNCTION__);
break;
default:
- fprintf(stderr, "%s: state %d\n", __FUNCTION__, state);
+ if (debug)
+ fprintf(stderr, "%s: state %d\n", __FUNCTION__, state);
+ break;
+ }
+}
+
+/* ---------------------------------------------------------------------- */
+
+static void service_type_browser_callback(AvahiServiceTypeBrowser *b,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiBrowserEvent event,
+ const char *type,
+ const char *domain,
+ AvahiLookupResultFlags flags,
+ void *userdata)
+{
+ char nif[32];
+
+ switch (event) {
+ case AVAHI_BROWSER_NEW:
+ ifname(nif, sizeof(nif), interface);
+ fprintf(stderr, " service: %s, %s, %s: %s\n",
+ nif, avahi_proto_to_string(protocol), domain, type);
+ break;
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ case AVAHI_BROWSER_FAILURE:
+ avahi_service_type_browser_free(b);
+ break;
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ /* don't log */
+ break;
+ default:
+ fprintf(stderr, "%s: %s (#%d)\n", __FUNCTION__,
+ bevents[event], event);
+ break;
+ }
+}
+
+static void domain_browser_callback(AvahiDomainBrowser *b,
+ AvahiIfIndex interface,
+ AvahiProtocol protocol,
+ AvahiBrowserEvent event,
+ const char *domain,
+ AvahiLookupResultFlags flags,
+ void *userdata)
+{
+ struct mdns_window *mdns = userdata;
+ char nif[32];
+
+ switch (event) {
+ case AVAHI_BROWSER_NEW:
+ ifname(nif, sizeof(nif), interface);
+ fprintf(stderr, " domain : %s, %s, %s\n",
+ nif, avahi_proto_to_string(protocol), domain);
+ avahi_service_type_browser_new(mdns->client,
+ interface, protocol, domain,
+ 0, service_type_browser_callback, mdns);
+ break;
+ case AVAHI_BROWSER_ALL_FOR_NOW:
+ case AVAHI_BROWSER_FAILURE:
+ avahi_domain_browser_free(b);
+ break;
+ case AVAHI_BROWSER_CACHE_EXHAUSTED:
+ /* don't log */
+ break;
+ default:
+ fprintf(stderr, "%s: %s (#%d)\n", __FUNCTION__,
+ bevents[event], event);
break;
}
}
+static void dump_stuff(struct mdns_window *mdns)
+{
+ const char *domain;
+
+ /* playground ... */
+ domain = avahi_client_get_domain_name(mdns->client);
+ fprintf(stderr, "default domain is \"%s\"\n", domain);
+ avahi_service_type_browser_new(mdns->client,
+ AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, domain,
+ 0, service_type_browser_callback, mdns);
+ avahi_domain_browser_new(mdns->client,
+ AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, NULL,
+ AVAHI_DOMAIN_BROWSER_BROWSE,
+ 0, domain_browser_callback, mdns);
+}
+
/* ---------------------------------------------------------------------- */
-int mdns_init(void)
+static void mdns_fini(struct mdns_window *mdns)
+{
+ if (mdns->client) {
+ if (debug)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+ avahi_client_free(mdns->client);
+ mdns->client = NULL;
+ }
+ if (mdns->glib_poll) {
+ avahi_glib_poll_free(mdns->glib_poll);
+ mdns->glib_poll = NULL;
+ }
+}
+
+static int mdns_init(struct mdns_window *mdns)
{
int error;
+ if (mdns->client)
+ return 0;
+ if (debug)
+ fprintf(stderr, "%s\n", __FUNCTION__);
+
/* Create the GLIB Adaptor */
avahi_set_allocator(avahi_glib_allocator());
- glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
- poll_api = avahi_glib_poll_get(glib_poll);
- client = avahi_client_new(poll_api, AVAHI_CLIENT_NO_FAIL,
- client_callback, NULL /* user data */,
- &error);
- if (client == NULL)
+ mdns->glib_poll = avahi_glib_poll_new(NULL, G_PRIORITY_DEFAULT);
+ mdns->poll_api = avahi_glib_poll_get(mdns->glib_poll);
+ mdns->client = avahi_client_new(mdns->poll_api, AVAHI_CLIENT_NO_FAIL,
+ client_callback, mdns,
+ &error);
+ if (mdns->client == NULL)
goto fail;
+
+ if (0)
+ dump_stuff(mdns);
return 0;
fail:
- mdns_fini();
+ mdns_fini(mdns);
return -1;
}
-int mdns_browse(const char *service, const char *domain)
+int mdns_browse(struct mdns_window *mdns,
+ const char *service, const char *domain)
{
- AvahiServiceBrowser *sb = NULL;
+ char label[256];
+
+ if (mdns->sb) {
+ avahi_service_browser_free(mdns->sb);
+ mdns->sb = NULL;
+ del_entries(mdns);
+ gtk_label_set_text(GTK_LABEL(mdns->status), "idle");
+ }
if (NULL == domain)
- domain = avahi_client_get_domain_name(client);
- sb = avahi_service_browser_new(client, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
- service, domain, 0, browse_callback, client);
- if (NULL == sb) {
+ domain = avahi_client_get_domain_name(mdns->client);
+ mdns->sb = avahi_service_browser_new(mdns->client,
+ AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC,
+ service, domain, 0,
+ browse_callback, mdns);
+ if (NULL == mdns->sb) {
fprintf(stderr, "%s: failed to create service browser: %s\n",
- __FUNCTION__, avahi_strerror(avahi_client_errno(client)));
+ __FUNCTION__, avahi_strerror(avahi_client_errno(mdns->client)));
return -1;
}
+ snprintf(label, sizeof(label),
+ "service \"%s\" in domain \"%s\"",
+ service, domain);
+ gtk_label_set_text(GTK_LABEL(mdns->status), label);
return 0;
}
-void mdns_fini(void)
+/* ---------------------------------------------------------------------- */
+
+static void menu_cb_close(GtkWidget *whatever, gpointer userdata)
+{
+ struct mdns_window *mdns = userdata;
+
+ gtk_widget_destroy(mdns->toplevel);
+}
+
+static void destroy(GtkWidget *widget,
+ gpointer data)
+{
+ struct mdns_window *mdns = data;
+
+ mdns_fini(mdns);
+ g_object_unref(mdns->store);
+ if (mdns->standalone)
+ gtk_main_quit();
+ free(mdns);
+}
+
+/* ---------------------------------------------------------------------- */
+
+static const GtkActionEntry entries[] = {
+ {
+ .name = "FileMenu",
+ .label = "_File",
+ },{
+ .name = "Close",
+ .stock_id = GTK_STOCK_CLOSE,
+ .label = "_Close",
+ .accelerator = "<control>Q",
+ .callback = G_CALLBACK(menu_cb_close),
+ },
+};
+
+static char ui_xml[] =
+"<ui>"
+" <menubar name='MainMenu'>"
+" <menu action='FileMenu'>"
+" <menuitem action='Close'/>"
+" </menu>"
+" </menubar>"
+" <toolbar action='ToolBar'>"
+" <toolitem action='Close'/>"
+" </toolbar>"
+"</ui>";
+
+/* ------------------------------------------------------------------ */
+
+static GtkWidget *mdns_create_view(struct mdns_window *mdns)
+{
+ GtkCellRenderer *renderer;
+ GtkWidget *view;
+
+ view = gtk_tree_view_new();
+ gtk_tree_view_set_model(GTK_TREE_VIEW(view),
+ GTK_TREE_MODEL(mdns->store));
+ gtk_tree_selection_set_mode(gtk_tree_view_get_selection(GTK_TREE_VIEW(view)),
+ GTK_SELECTION_SINGLE);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "name", renderer,
+ "text", ST_COL_NAME,
+ NULL);
+
+#if 0
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "type", renderer,
+ "text", ST_COL_TYPE,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "domain", renderer,
+ "text", ST_COL_DOMAIN,
+ NULL);
+#endif
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "if", renderer,
+ "text", ST_COL_INTERFACE,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "proto", renderer,
+ "text", ST_COL_PROTOCOL,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "hostname", renderer,
+ "text", ST_COL_HOSTNAME,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ g_object_set(renderer,
+ "xalign", 1.0,
+ NULL);
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "address", renderer,
+ "text", ST_COL_ADDR,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "port", renderer,
+ "text", ST_COL_PORT,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "path", renderer,
+ "text", ST_COL_PATH,
+ NULL);
+
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "url", renderer,
+ "text", ST_COL_URL,
+ NULL);
+
+ /* fill remaining space */
+ renderer = gtk_cell_renderer_text_new();
+ gtk_tree_view_insert_column_with_attributes
+ (GTK_TREE_VIEW(view), -1, "", renderer,
+ NULL);
+
+ return view;
+}
+
+struct mdns_window *mdns_create_window(int standalone)
{
- if (client) {
- avahi_client_free(client);
- client = NULL;
+ struct mdns_window *mdns;
+ GtkWidget *vbox, *menubar, *toolbar, *scroll;
+ GtkAccelGroup *accel;
+ GtkActionGroup *ag;
+ GtkUIManager *ui;
+ GError *err;
+
+ mdns = malloc(sizeof(*mdns));
+ memset(mdns,0,sizeof(*mdns));
+ if (-1 == mdns_init(mdns)) {
+ free(mdns);
+ return NULL;
}
- if (glib_poll) {
- avahi_glib_poll_free(glib_poll);
- glib_poll = NULL;
+ mdns->standalone = standalone;
+
+ mdns->toplevel = gtk_window_new(GTK_WINDOW_TOPLEVEL);
+ gtk_window_set_title(GTK_WINDOW(mdns->toplevel), "mdns");
+ gtk_widget_set_size_request(GTK_WIDGET(mdns->toplevel), 480, 320);
+ g_signal_connect(G_OBJECT(mdns->toplevel), "destroy",
+ G_CALLBACK(destroy), mdns);
+
+ /* menu + toolbar */
+ ui = gtk_ui_manager_new();
+ ag = gtk_action_group_new("MenuActions");
+ gtk_action_group_add_actions(ag, entries, G_N_ELEMENTS(entries), mdns);
+ gtk_ui_manager_insert_action_group(ui, ag, 0);
+ accel = gtk_ui_manager_get_accel_group(ui);
+ gtk_window_add_accel_group(GTK_WINDOW(mdns->toplevel), accel);
+
+ err = NULL;
+ if (!gtk_ui_manager_add_ui_from_string(ui, ui_xml, -1, &err)) {
+ g_message("building menus failed: %s", err->message);
+ g_error_free(err);
+ exit(1);
}
+
+ /* list */
+ mdns->store = gtk_list_store_new(ST_NUM_COLS,
+ G_TYPE_STRING, // ST_COL_NAME
+ G_TYPE_STRING, // ST_COL_TYPE
+ G_TYPE_STRING, // ST_COL_DOMAIN
+ G_TYPE_STRING, // ST_COL_INTERFACE
+ G_TYPE_STRING, // ST_COL_PROTOCOL
+
+ G_TYPE_STRING, // ST_COL_HOSTNAME
+ G_TYPE_STRING, // ST_COL_ADDR
+ G_TYPE_STRING, // ST_COL_PORT
+ G_TYPE_STRING, // ST_COL_PATH
+
+ G_TYPE_STRING); // ST_COL_URL
+ mdns->view = mdns_create_view(mdns);
+#if 0
+ g_signal_connect(mdns->view, "row-activated", G_CALLBACK(activate), mdns);
+#endif
+ scroll = gtk_scrolled_window_new(NULL, NULL);
+ gtk_scrolled_window_set_policy(GTK_SCROLLED_WINDOW(scroll),
+ GTK_POLICY_NEVER,
+ GTK_POLICY_AUTOMATIC);
+
+ /* other widgets */
+ mdns->status = gtk_widget_new(GTK_TYPE_LABEL,
+ "label", "status line",
+ "xalign", 0.0,
+ NULL);
+
+ /* Make a vbox and put stuff in */
+ vbox = gtk_vbox_new(FALSE, 1);
+ gtk_container_set_border_width(GTK_CONTAINER(vbox), 1);
+ gtk_container_add(GTK_CONTAINER(mdns->toplevel), vbox);
+ menubar = gtk_ui_manager_get_widget(ui, "/MainMenu");
+ gtk_box_pack_start(GTK_BOX(vbox), menubar, FALSE, FALSE, 0);
+ toolbar = gtk_ui_manager_get_widget(ui, "/ToolBar");
+ gtk_box_pack_start(GTK_BOX(vbox), toolbar, FALSE, FALSE, 0);
+ gtk_box_pack_start(GTK_BOX(vbox), scroll, TRUE, TRUE, 0);
+ gtk_container_add(GTK_CONTAINER(scroll), mdns->view);
+ gtk_box_pack_end(GTK_BOX(vbox), mdns->status, FALSE, TRUE, 0);
+
+ return mdns;
}
-#else
+void mdns_show_window(struct mdns_window *mdns)
+{
+ gtk_widget_show_all(mdns->toplevel);
+}
-int mdns_init(void)
+void mdns_destroy_window(struct mdns_window *mdns)
{
- return -1;
+ gtk_widget_destroy(mdns->toplevel);
}
-int mdns_browse(const char *service, const char *domain)
+/* ---------------------------------------------------------------------- */
+
+#else /* ! HAVE_AVAHI */
+
+struct mdns_window *mdns_create_window(void)
{
- return -1;
+ return NULL;
}
-void mdns_fini(void)
+void mdns_show_window(struct mdns_window *mdns) {}
+void mdns_destroy_window(struct mdns_window *mdns) {}
+
+int mdns_browse(struct mdns_window *mdns,
+ const char *service, const char *domain)
{
+ return -1;
}
#endif
diff --git a/mdns.h b/mdns.h
index 7729380..0d41d39 100644
--- a/mdns.h
+++ b/mdns.h
@@ -1,3 +1,8 @@
-int mdns_init(void);
-int mdns_browse(const char *service, const char *domain);
-void mdns_fini(void);
+struct mdns_window;
+
+struct mdns_window *mdns_create_window(int standalone);
+void mdns_show_window(struct mdns_window *mdns);
+void mdns_destroy_window(struct mdns_window *mdns);
+
+int mdns_browse(struct mdns_window *mdns,
+ const char *service, const char *domain);
diff --git a/xd_view.c b/xd_view.c
index 3287793..82d841a 100644
--- a/xd_view.c
+++ b/xd_view.c
@@ -16,6 +16,7 @@
#include "xd_store.h"
#include "xenviews.h"
#include "tcp.h"
+#include "mdns.h"
#define XENCONSOLE "/usr/lib/xen/bin/xenconsole"
@@ -420,6 +421,23 @@ static void menu_cb_xenstore(void)
gtk_widget_show_all(xs_toplevel);
}
+static void menu_cb_mdns(void)
+{
+#ifdef HAVE_AVAHI
+ struct mdns_window *mdns;
+
+ mdns = mdns_create_window(0);
+ if (NULL == mdns) {
+ gtk_message(GTK_MESSAGE_ERROR, "Can't setup mDNS browser, sorry.\n");
+ return;
+ }
+ mdns_browse(mdns, "_workstation._tcp", NULL);
+ mdns_show_window(mdns);
+#else
+ gtk_message(GTK_MESSAGE_ERROR, "Compiled without mDNS support, sorry.\n");
+#endif
+}
+
static void menu_cb_open_vnc(void)
{
char *name, *tty, *ostype;
@@ -541,12 +559,6 @@ static const GtkActionEntry entries[] = {
.callback = menu_cb_about,
},{
- .name = "Xenstore",
- .label = "_Xenstore browser",
- .accelerator = "<control>X",
- .callback = menu_cb_xenstore,
- },{
-
.name = "OpenVNC",
.label = "_VNC",
.accelerator = "<control>V",
@@ -601,6 +613,16 @@ static const GtkActionEntry entries[] = {
.label = "_Destroy",
.tooltip = "Radically kill off domain",
.callback = menu_cb_domain_destroy,
+ },{
+
+ .name = "Xenstore",
+ .label = "_Xenstore browser",
+ .accelerator = "<control>X",
+ .callback = menu_cb_xenstore,
+ },{
+ .name = "mDNS",
+ .label = "mDNS browser",
+ .callback = menu_cb_mdns,
},
};
@@ -624,6 +646,7 @@ static char ui_xml[] =
" </menu>"
" <menu action='WindowMenu'>"
" <menuitem action='Xenstore'/>"
+" <menuitem action='mDNS'/>"
" </menu>"
" <menu action='HelpMenu'>"
" <menuitem action='About'/>"
diff --git a/xenwatch.c b/xenwatch.c
index 6f56c74..c58f6de 100644
--- a/xenwatch.c
+++ b/xenwatch.c
@@ -12,7 +12,6 @@
#include <gtk/gtk.h>
#include "xenviews.h"
-#include "mdns.h"
/* ------------------------------------------------------------------ */
@@ -24,7 +23,6 @@ int
main(int argc, char *argv[])
{
setlocale(LC_ALL,"");
-
gtk_init(&argc, &argv);
dpy = gdk_x11_display_get_xdisplay(gdk_display_get_default());
fcntl(ConnectionNumber(dpy),F_SETFD,FD_CLOEXEC);
@@ -32,12 +30,7 @@ main(int argc, char *argv[])
xen_doms_create_window();
gtk_widget_show_all(xd_toplevel);
- mdns_init();
- mdns_browse("_ssh._tcp", NULL);
-
gtk_main();
-
- mdns_fini();
fprintf(stderr,"bye...\n");
exit(0);
}