#include "rodisc.h" #include #include static GaClient *mdns_client; static GaEntryGroup *mdns_group; static GaEntryGroupService *mdns_service; static guint disc_change_count = 0; static void mdns_service_freeze() { g_return_if_fail(mdns_service); ga_entry_group_service_freeze(mdns_service); } static void mdns_service_thaw() { GError *error = NULL; g_return_if_fail(mdns_service); if (!ga_entry_group_service_thaw(mdns_service, &error)) { g_warning("Could not update service TXT entries: %s", error->message); g_error_free(error); } } static void mdns_service_update() { GError *error = NULL; g_return_if_fail(mdns_service); // "sys=waMA=00:00:00:00:00:00,adVF=0x4,adDT=0x2,adCC=0" // waMA = MAC address // adVF = Volume flags (0x200 "ask me first") // adDT = Supported media? // adCC = Disc change count? guint flags = 0; guint media = 2; gchar *record = g_strdup_printf("waMA=00:00:00:00:00:00,adVF=0x%x,adDT=0x%x,adCC=%u", flags, media, disc_change_count); if (!ga_entry_group_service_set(mdns_service, "sys", record, &error)) { g_warning("Could not update main TXT record: %s", error->message); g_error_free(error); } g_free(record); } static void mdns_service_update_disc(RODisc *disc) { GError *error = NULL; g_return_if_fail(mdns_service); // "CdRom0=adVN=DiscLabel,adVT=public.cd-media" gchar *record = g_strdup_printf("adVN=%s,adVT=%s", disc->label, disc->type); const gchar *uri_basename = &disc->uri[1]; // Skip first '/' if (!ga_entry_group_service_set(mdns_service, uri_basename, record, &error)) { g_warning("Could not update TXT record for disc at '%s': %s", disc->uri, error->message); g_error_free(error); } g_free(record); } static void mdns_service_remove_disc(RODisc *disc) { GError *error = NULL; g_return_if_fail(mdns_service); const gchar *uri_basename = &disc->uri[1]; if (!ga_entry_group_service_remove_key(mdns_service, uri_basename, &error)) { g_warning("Could not update TXT record for disc at '%s': %s", disc->uri, error->message); g_error_free(error); } } static void mdns_register_service() { GError * error = NULL; if (!mdns_group) { mdns_group = ga_entry_group_new(); if (!ga_entry_group_attach(mdns_group, mdns_client, &error)) { g_warning("Could not attach MDNS group to client: %s", error->message); g_error_free(error); return; } } const gchar *name = avahi_client_get_host_name(mdns_client->avahi_client); const unsigned int port = server_get_port(); mdns_service = ga_entry_group_add_service(mdns_group, name, RODISC_MDNS_SERVICE, port, &error, NULL); if (!mdns_service) { g_warning("Could not create service: %s", error->message); g_error_free(error); return; } // Create TXT records, disc records, etc. mdns_service_update(); rodisc_refresh_all(); if (!ga_entry_group_commit(mdns_group, &error)) { g_warning("Could not announce MDNS service: %s", error->message); g_error_free(error); return; } } static void mdns_client_state_changed_cb(GaClient *client, GaClientState state, gpointer user_data) { switch (state) { case GA_CLIENT_STATE_FAILURE: g_warning("MDNS client state failure"); break; case GA_CLIENT_STATE_S_RUNNING: g_debug("MDNS client found server running"); mdns_register_service(); break; case GA_CLIENT_STATE_S_COLLISION: case GA_CLIENT_STATE_S_REGISTERING: g_message("MDNS collision"); if (mdns_group) { ga_entry_group_reset(mdns_group, NULL); mdns_service = 0; } break; default: // Do nothing break; } } bool mdns_start() { GError *error = NULL; mdns_client = ga_client_new(GA_CLIENT_FLAG_NO_FLAGS); g_signal_connect(mdns_client, "state-changed", G_CALLBACK(mdns_client_state_changed_cb), NULL); if (!ga_client_start(mdns_client, &error)) { g_printerr("Could not start MDNS client: %s\n", error->message); g_error_free(error); return false; } return true; } void mdns_stop() { g_object_unref(mdns_client); } void mdns_publish(RODisc *disc) { mdns_service_freeze(); disc_change_count++; mdns_service_update_disc(disc); mdns_service_update(); mdns_service_thaw(); } void mdns_unpublish(RODisc *disc) { mdns_service_freeze(); disc_change_count++; mdns_service_remove_disc(disc); mdns_service_update(); mdns_service_thaw(); }