aboutsummaryrefslogtreecommitdiffstats
path: root/mdns-publish-vnc.c
diff options
context:
space:
mode:
Diffstat (limited to 'mdns-publish-vnc.c')
-rw-r--r--mdns-publish-vnc.c238
1 files changed, 238 insertions, 0 deletions
diff --git a/mdns-publish-vnc.c b/mdns-publish-vnc.c
new file mode 100644
index 0000000..1a88fa0
--- /dev/null
+++ b/mdns-publish-vnc.c
@@ -0,0 +1,238 @@
+#include <stdio.h>
+#include <stdlib.h>
+#include <stdarg.h>
+#include <string.h>
+#include <unistd.h>
+#include <signal.h>
+#include <fcntl.h>
+#include <time.h>
+#include <sys/syslog.h>
+#include <sys/utsname.h>
+
+#include <xs.h>
+
+#include "list.h"
+#include "xenstore.h"
+#include "mdns-publish.h"
+
+/* ------------------------------------------------------------- */
+
+struct dom {
+ int domid;
+ char name[128];
+ int destroyed;
+
+ char label[256];
+ int vnc_port;
+ int published;
+ struct mdns_pub_entry *entry;
+
+ struct list_head next;
+};
+
+static LIST_HEAD(doms);
+static struct utsname uts;
+
+/* ------------------------------------------------------------- */
+
+static struct dom *find_dom(int domid)
+{
+ struct dom *dom;
+ struct list_head *item;
+
+ list_for_each(item, &doms) {
+ dom = list_entry(item, struct dom, next);
+ if (dom->domid == domid)
+ return dom;
+ }
+ return NULL;
+}
+
+static struct dom *get_dom(int domid)
+{
+ struct dom *dom;
+
+ dom = find_dom(domid);
+ if (!dom) {
+ dom = malloc(sizeof(*dom));
+ memset(dom,0,sizeof(*dom));
+ dom->domid = domid;
+ list_add_tail(&dom->next, &doms);
+ }
+ return dom;
+}
+
+static void try_attach_domain(struct mdns_pub *mdns, struct dom *dom, int boot)
+{
+ if (dom->published)
+ return;
+ if (!strlen(dom->name))
+ return;
+ if (!dom->vnc_port)
+ return;
+
+ snprintf(dom->label, sizeof(dom->label), "host %s, guest %s",
+ uts.nodename, dom->name);
+ mdns_log_printf(mdns, LOG_INFO, "pub: %s (%d)\n", dom->name, dom->domid);
+ dom->entry = mdns_pub_add(mdns, dom->label, "_rfb._tcp", dom->vnc_port);
+
+ dom->published = 1;
+}
+
+static void try_release_domain(struct mdns_pub *mdns, struct dom *dom)
+{
+ if (!dom->destroyed)
+ return;
+ if (dom->published) {
+ mdns_log_printf(mdns, LOG_INFO, "del: %s (%d)\n", dom->name, dom->domid);
+ mdns_pub_del(dom->entry);
+ }
+ list_del(&dom->next);
+ free(dom);
+}
+
+/* ------------------------------------------------------------- */
+
+static void usage(FILE *fp)
+{
+ fprintf(fp, "usage: [fixme]\n");
+}
+
+int main(int argc, char *argv[])
+{
+ struct mdns_pub *mdns = NULL;
+ struct xs_handle *xenstore = NULL;
+ xs_transaction_t xst;
+ char **vec = NULL;
+ int domid, c;
+ int debug = 0;
+ char path[128], value[128];
+ unsigned int count, i, rc;
+ struct dom *dom;
+ fd_set set;
+
+ for (;;) {
+ if (-1 == (c = getopt(argc, argv, "hd")))
+ break;
+ switch (c) {
+
+ case 'd':
+ debug++;
+ break;
+
+ case 'h':
+ usage(stdout);
+ exit(0);
+ default:
+ usage(stderr);
+ exit(1);
+ }
+ }
+
+ mdns_pub_appname = "mdns-publish-vnc";
+ uname(&uts);
+ if (!debug)
+ mdns_daemonize();
+
+ /* connect to xenstore */
+ xenstore = xenstore_open(1,1,1,1);
+ if (NULL == xenstore) {
+ mdns_log_printf(mdns, LOG_ERR, "can't access xenstore, exiting\n");
+ exit(1);
+ }
+ xs_watch(xenstore, "/local/domain", "token");
+
+ mdns = mdns_pub_init(debug);
+ if (NULL == mdns)
+ exit(1);
+ mdns_sigsetup(mdns);
+ mdns_pub_start(mdns);
+
+ /* look for running domains */
+ if (!(xst = xs_transaction_start(xenstore))) {
+ mdns_log_printf(mdns, LOG_ERR, "Oops, can't start xenstore transaction\n");
+ exit(1);
+ }
+ vec = xs_directory(xenstore, xst, "/local/domain", &count);
+ xs_transaction_end(xenstore, xst, 0);
+
+ fprintf(stderr,"looking for existing domains\n");
+ for (i = 0; i < count; i++) {
+ domid = atoi(vec[i]);
+ dom = get_dom(domid);
+ snprintf(path, sizeof(path), "/local/domain/%d/name", domid);
+ xenstore_read(xenstore, path, dom->name, sizeof(dom->name));
+ snprintf(path, sizeof(path), "/local/domain/%d/console/vnc-port", domid);
+ if (0 == xenstore_read(xenstore, path, value, sizeof(value)))
+ dom->vnc_port = atoi(value);
+ try_attach_domain(mdns, dom, 1);
+ }
+
+ /* main loop */
+ fprintf(stderr,"ok, watching out for changes now\n");
+ for (;;) {
+ if (mdns_pub_appquit)
+ break;
+
+ FD_ZERO(&set);
+ FD_SET(xs_fileno(xenstore), &set);
+ switch (select(xs_fileno(xenstore)+1, &set, NULL, NULL, NULL)) {
+ case -1:
+ if (EINTR == errno)
+ continue; /* termsig check */
+ perror("select");
+ break;
+ case 0:
+ fprintf(stderr,"Huh, select() timeout?\n");
+ mdns_pub_appquit++;
+ break;
+ default:
+ break;
+ }
+
+ if (vec)
+ free(vec);
+ vec = xs_read_watch(xenstore, &count);
+ if (NULL == vec) {
+ fprintf(stderr,"xs_read_watch() failed\n");
+ exit(1);
+ }
+ if (2 != sscanf(vec[XS_WATCH_PATH], "/local/domain/%d/%64s", &domid, path)) {
+ if (1 != sscanf(vec[XS_WATCH_PATH], "/local/domain/%d", &domid))
+ continue;
+ strcpy(path, "");
+ }
+ dom = get_dom(domid);
+
+ if (0 == strcmp(path,"")) {
+ rc = xenstore_read(xenstore, vec[XS_WATCH_PATH], value, sizeof(value));
+ if (0 != rc)
+ dom->destroyed = 1;
+
+ } else if (0 == strcmp(path, "name")) {
+ rc = xenstore_read(xenstore, vec[XS_WATCH_PATH], value, sizeof(value));
+ if (0 != rc)
+ continue;
+ strcpy(dom->name, value);
+ mdns_log_printf(mdns, LOG_INFO, "new: %s (%d)\n", dom->name, dom->domid);
+
+ } else if (0 == strcmp(path, "console/vnc-port")) {
+ rc = xenstore_read(xenstore, vec[XS_WATCH_PATH], value, sizeof(value));
+ if (0 != rc)
+ continue;
+ dom->vnc_port = atoi(value);
+
+ } else {
+ continue;
+
+ }
+
+ try_attach_domain(mdns, dom, 0);
+ try_release_domain(mdns, dom);
+ }
+
+ mdns_pub_del_all(mdns);
+ mdns_pub_stop(mdns);
+ mdns_pub_fini(mdns);
+ return 0;
+}