#include #include #include #include #include #include #include #include #include #include #include #include "list.h" #include "xs_tools.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), "Xen guest %s (%s, #%d)", dom->name, uts.nodename, dom->domid); 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, NULL); 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; }