/* -- avahi.c -- */ #include "x11vnc.h" void avahi_initialise(void); void avahi_advertise(const char *name, const char *host, const uint16_t port); void avahi_reset(void); void avahi_cleanup(void); static pid_t avahi_pid = 0; static void kill_avahi_pid(void) { if (avahi_pid != 0) { kill(avahi_pid, SIGTERM); avahi_pid = 0; } } static int try_avahi_helper(const char *name, const char *host, const uint16_t port) { #if LIBVNCSERVER_HAVE_FORK char *cmd, *p, *path = getenv("PATH"), portstr[32]; int i; /* avahi-publish */ if (no_external_cmds || !cmd_ok("zeroconf")) { return 0; } if (!path) { return 0; } path = strdup(path); cmd = (char *) malloc(strlen(path) + 100); sprintf(portstr, "%d", (int) port); p = strtok(path, ":"); while (p) { struct stat sbuf; sprintf(cmd, "%s/avahi-publish", p); if (stat(cmd, &sbuf) == 0) { break; } sprintf(cmd, "%s/dns-sd", p); if (stat(cmd, &sbuf) == 0) { break; } sprintf(cmd, "%s/mDNS", p); if (stat(cmd, &sbuf) == 0) { break; } cmd[0] = '\0'; p = strtok(NULL, ":"); } free(path); if (!strcmp(cmd, "")) { free(cmd); rfbLog("Could not find an external avahi/zeroconf helper program.\n"); return 0; } avahi_pid = fork(); if (avahi_pid < 0) { rfbLogPerror("fork"); avahi_pid = 0; free(cmd); return 0; } if (avahi_pid != 0) { int status; usleep(500 * 1000); waitpid(avahi_pid, &status, WNOHANG); if (kill(avahi_pid, 0) != 0) { waitpid(avahi_pid, &status, WNOHANG); avahi_pid = 0; free(cmd); return 0; } if (! quiet) { rfbLog("%s helper pid is: %d\n", cmd, (int) avahi_pid); } free(cmd); return 1; } for (i=3; i<256; i++) { close(i); } if (strstr(cmd, "/avahi-publish")) { execlp(cmd, cmd, "-s", name, "_rfb._tcp", portstr, (char *) NULL); } else { execlp(cmd, cmd, "-R", name, "_rfb._tcp", ".", portstr, (char *) NULL); } exit(1); #else if (!name || !host || !port) {} return 0; #endif } #if !defined(LIBVNCSERVER_HAVE_AVAHI) || !defined(LIBVNCSERVER_HAVE_LIBPTHREAD) void avahi_initialise(void) { rfbLog("avahi_initialise: no Avahi support at buildtime.\n"); } void avahi_advertise(const char *name, const char *host, const uint16_t port) { if (!try_avahi_helper(name, host, port)) { rfbLog("avahi_advertise: no Avahi support at buildtime.\n"); avahi = 0; } } void avahi_reset(void) { kill_avahi_pid(); rfbLog("avahi_reset: no Avahi support at buildtime.\n"); } void avahi_cleanup(void) { kill_avahi_pid(); rfbLog("avahi_cleanup: no Avahi support at buildtime.\n"); } #else #include #include #include #include static AvahiThreadedPoll *_poll = NULL; static AvahiClient *_client = NULL; static AvahiEntryGroup *_group = NULL; static int db = 0; typedef struct { const char *name; const char *host; uint16_t port; } avahi_service_t; typedef struct { char *name; char *host; uint16_t port; } avahi_reg_t; #define NREG 16 static avahi_reg_t registered[NREG]; void avahi_initialise(void) { int ret; static int first = 1; if (getenv("AVAHI_DEBUG")) { db = 1; } if (first) { int i; for (i=0; iname); #if 0 /* is this the segv problem? */ free(svc); #endif break; case AVAHI_ENTRY_GROUP_COLLISION: new_name = avahi_alternative_service_name(svc->name); _avahi_create_services(new_name, svc->host, svc->port); rfbLog("Avahi Entry group collision\n"); avahi_free(new_name); break; case AVAHI_ENTRY_GROUP_FAILURE: rfbLog("Avahi Entry group failure: %s\n", avahi_strerror(avahi_client_errno( avahi_entry_group_get_client(g)))); break; } if (db) fprintf(stderr, "out _avahi_entry_group_callback\n"); } static void _avahi_create_services(const char *name, const char *host, const uint16_t port) { avahi_service_t *svc = (avahi_service_t *)malloc(sizeof(avahi_service_t)); int ret = 0; if (db) fprintf(stderr, "in _avahi_create_services %s %s %d\n", name, host, port); svc->name = name; svc->host = host; svc->port = port; if (!_group) { if (db) fprintf(stderr, " _avahi_create_services create group\n"); _group = avahi_entry_group_new(_client, _avahi_entry_group_callback, svc); } if (!_group) { rfbLog("avahi_entry_group_new() failed: %s\n", avahi_strerror(avahi_client_errno(_client))); return; } ret = avahi_entry_group_add_service(_group, AVAHI_IF_UNSPEC, AVAHI_PROTO_UNSPEC, 0, name, "_rfb._tcp", NULL, NULL, port, NULL); if (ret < 0) { rfbLog("Failed to add _rfb._tcp service: %s\n", avahi_strerror(ret)); return; } ret = avahi_entry_group_commit(_group); if (ret < 0) { rfbLog("Failed to commit entry_group:: %s\n", avahi_strerror(ret)); return; } if (db) fprintf(stderr, "out _avahi_create_services\n"); } void avahi_advertise(const char *name, const char *host, const uint16_t port) { int i; if (db) fprintf(stderr, "in avahi_advertise: %s %s %d\n", name, host, port); if (!_client) { if (db) fprintf(stderr, " avahi_advertise client null\n"); return; } if (_poll == NULL) { rfbLog("Avahi poll not initialized.\n"); return; } /* well, we just track it ourselves... */ for (i=0; i= 5900 ? port : 5900+port); avahi_threaded_poll_unlock(_poll); if (db) fprintf(stderr, "out avahi_advertise\n"); } void avahi_reset(void) { int i; if (db) fprintf(stderr, "in avahi_reset\n"); for (i=0; i