Commit 7071bbd5 authored by W. Michael Petullo's avatar W. Michael Petullo

Allow two DMAP sub-protocols (e.g., DAAP and DPAP) in one process

DmapMdnsPublisher is now a singleton class that stores a running list
of services. This ensures that one DMAP sub-protocol does not unpublish
another when avahi_entry_group_reset() is called.
Signed-off-by: W. Michael Petullo's avatarW. Michael Petullo <mike@flyn.org>
parent 5ea14027
09 September 2010 W. Michael Petullo <mike@flyn.org>
* Allow two sub-DMAP protocols (e.g., DAAP and DPAP) in one
process.
07 September 2010 W. Michael Petullo <mike@flyn.org>
* Allow dmap-mdns-*-dnssd.c to compile.
......
Complete DACP code and push Rhythmbox patch
Allow both DPAP and DAAP sharing in one process (using two threads
instead of two processes).
Reduce the memory usage while building response to media list query.
Replace dmap-md5.[ch] with GChecksum.
......
......@@ -46,11 +46,8 @@ static void dmap_mdns_publisher_finalize (GObject *object);
#define DMAP_MDNS_PUBLISHER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), TYPE_DMAP_MDNS_PUBLISHER, DmapMdnsPublisherPrivate))
struct DmapMdnsPublisherPrivate
struct DmapMdnsPublisherService
{
AvahiClient *client;
AvahiEntryGroup *entry_group;
char *name;
guint port;
char *type_of_service;
......@@ -58,6 +55,13 @@ struct DmapMdnsPublisherPrivate
gchar **txt_records;
};
struct DmapMdnsPublisherPrivate
{
AvahiClient *client;
AvahiEntryGroup *entry_group;
GSList *service;
};
enum {
PUBLISHED,
NAME_COLLISION,
......@@ -84,57 +88,39 @@ dmap_mdns_publisher_error_quark (void)
return quark;
}
static void
emit_published (char *name, DmapMdnsPublisher *publisher)
{
g_signal_emit (publisher, signals [PUBLISHED], 0, name);
}
static void
entry_group_cb (AvahiEntryGroup *group,
AvahiEntryGroupState state,
DmapMdnsPublisher *publisher)
{
if (state == AVAHI_ENTRY_GROUP_ESTABLISHED) {
g_signal_emit (publisher, signals [PUBLISHED], 0, publisher->priv->name);
g_slist_foreach (publisher->priv->service, (GFunc) emit_published, publisher);
} else if (state == AVAHI_ENTRY_GROUP_COLLISION) {
g_warning ("MDNS name collision");
/* FIXME: how to know which name collided?
g_signal_emit (publisher, signals [NAME_COLLISION], 0, publisher->priv->name);
*/
g_signal_emit (publisher, signals [NAME_COLLISION], 0, "unknown");
}
}
static gboolean
create_service (DmapMdnsPublisher *publisher,
GError **error)
create_service (struct DmapMdnsPublisherService *service,
DmapMdnsPublisher *publisher,
GError **error)
{
int ret;
int ret;
const char *password_record;
AvahiStringList *txt_records;
if (publisher->priv->entry_group == NULL) {
publisher->priv->entry_group = avahi_entry_group_new (publisher->priv->client,
(AvahiEntryGroupCallback)entry_group_cb,
publisher);
dmap_mdns_avahi_set_entry_group (publisher->priv->entry_group);
} else {
avahi_entry_group_reset (publisher->priv->entry_group);
}
if (publisher->priv->entry_group == NULL) {
g_warning ("Could not create AvahiEntryGroup for publishing");
g_set_error (error,
DMAP_MDNS_PUBLISHER_ERROR,
DMAP_MDNS_PUBLISHER_ERROR_FAILED,
"%s",
_("Could not create AvahiEntryGroup for publishing"));
return FALSE;
}
#if 0
g_message ("Service name:%s port:%u password:%d",
publisher->priv->name,
publisher->priv->port,
publisher->priv->password_required);
#endif
if (publisher->priv->password_required) {
if (service->password_required) {
password_record = "Password=true";
} else {
password_record = "Password=false";
......@@ -142,9 +128,9 @@ create_service (DmapMdnsPublisher *publisher,
txt_records = avahi_string_list_new(password_record, NULL);
if (publisher->priv->txt_records) {
//g_debug("Number of txt records: %d", publisher->priv->txt_records);
gchar **txt_record = publisher->priv->txt_records;
if (service->txt_records) {
//g_debug("Number of txt records: %d", service->txt_records);
gchar **txt_record = service->txt_records;
while (*txt_record) {
txt_records = avahi_string_list_add(txt_records, *txt_record);
txt_record++;
......@@ -155,11 +141,11 @@ create_service (DmapMdnsPublisher *publisher,
AVAHI_IF_UNSPEC,
AVAHI_PROTO_UNSPEC,
0,
publisher->priv->name,
publisher->priv->type_of_service,
service->name,
service->type_of_service,
NULL,
NULL,
publisher->priv->port,
service->port,
txt_records);
avahi_string_list_free(txt_records);
......@@ -174,155 +160,92 @@ create_service (DmapMdnsPublisher *publisher,
return FALSE;
}
ret = avahi_entry_group_commit (publisher->priv->entry_group);
if (ret < 0) {
g_set_error (error,
DMAP_MDNS_PUBLISHER_ERROR,
DMAP_MDNS_PUBLISHER_ERROR_FAILED,
"%s: %s",
_("Could not commit service"),
avahi_strerror (ret));
return FALSE;
}
return TRUE;
}
static gboolean
refresh_service (DmapMdnsPublisher *publisher,
create_services (DmapMdnsPublisher *publisher,
GError **error)
{
return create_service (publisher, error);
}
static gboolean
publisher_set_name_internal (DmapMdnsPublisher *publisher,
const char *name,
GError **error)
{
g_free (publisher->priv->name);
publisher->priv->name = g_strdup (name);
return TRUE;
}
gboolean
dmap_mdns_publisher_set_name (DmapMdnsPublisher *publisher,
const char *name,
GError **error)
{
g_return_val_if_fail (publisher != NULL, FALSE);
publisher_set_name_internal (publisher, name, error);
GSList *ptr;
int ret;
if (publisher->priv->entry_group) {
refresh_service (publisher, error);
if (publisher->priv->entry_group == NULL) {
publisher->priv->entry_group = avahi_entry_group_new (publisher->priv->client,
(AvahiEntryGroupCallback)entry_group_cb,
publisher);
dmap_mdns_avahi_set_entry_group (publisher->priv->entry_group);
} else {
avahi_entry_group_reset (publisher->priv->entry_group);
}
return TRUE;
}
static gboolean
publisher_set_port_internal (DmapMdnsPublisher *publisher,
guint port,
GError **error)
{
publisher->priv->port = port;
return TRUE;
}
gboolean
dmap_mdns_publisher_set_port (DmapMdnsPublisher *publisher,
guint port,
GError **error)
{
g_return_val_if_fail (publisher != NULL, FALSE);
publisher_set_port_internal (publisher, port, error);
if (publisher->priv->entry_group) {
refresh_service (publisher, error);
if (publisher->priv->entry_group == NULL) {
g_warning ("Could not create AvahiEntryGroup for publishing");
g_set_error (error,
DMAP_MDNS_PUBLISHER_ERROR,
DMAP_MDNS_PUBLISHER_ERROR_FAILED,
"%s",
_("Could not create AvahiEntryGroup for publishing"));
return FALSE;
}
return TRUE;
}
static gboolean
publisher_set_type_of_service_internal (DmapMdnsPublisher *publisher,
const char *type_of_service,
GError **error)
{
g_free (publisher->priv->type_of_service);
publisher->priv->type_of_service = g_strdup (type_of_service);
return TRUE;
}
gboolean
dmap_mdns_publisher_set_type_of_service (DmapMdnsPublisher *publisher,
const char *type_of_service,
GError **error)
{
g_return_val_if_fail (publisher != NULL, FALSE);
for (ptr = publisher->priv->service; ptr; ptr = g_slist_next (ptr)) {
if (! create_service (ptr->data, publisher, error)) {
return FALSE;
}
}
publisher_set_type_of_service_internal (publisher, type_of_service, error);
ret = avahi_entry_group_commit (publisher->priv->entry_group);
if (publisher->priv->entry_group) {
refresh_service (publisher, error);
if (ret < 0) {
g_set_error (error,
DMAP_MDNS_PUBLISHER_ERROR,
DMAP_MDNS_PUBLISHER_ERROR_FAILED,
"%s: %s",
_("Could not commit service"),
avahi_strerror (ret));
return FALSE;
}
return TRUE;
}
static gboolean
publisher_set_password_required_internal (DmapMdnsPublisher *publisher,
gboolean required,
GError **error)
refresh_services (DmapMdnsPublisher *publisher,
GError **error)
{
publisher->priv->password_required = required;
return TRUE;
return create_services (publisher, error);
}
gboolean
dmap_mdns_publisher_set_password_required (DmapMdnsPublisher *publisher,
gboolean required,
GError **error)
dmap_mdns_publisher_rename_at_port (DmapMdnsPublisher *publisher,
guint port,
const char *name,
GError **error)
{
g_return_val_if_fail (publisher != NULL, FALSE);
GSList *ptr;
publisher_set_password_required_internal (publisher, required, error);
g_return_val_if_fail (publisher != NULL, FALSE);
if (publisher->priv->entry_group) {
refresh_service (publisher, error);
for (ptr = publisher->priv->service; ptr; ptr = g_slist_next (ptr)) {
if (port == ((struct DmapMdnsPublisherService *) ptr->data)->port)
break;
}
return TRUE;
}
static gboolean
publisher_set_txt_records_internal (DmapMdnsPublisher *publisher,
gchar **txt_records,
GError **error)
{
g_strfreev (publisher->priv->txt_records);
publisher->priv->txt_records = g_strdupv (txt_records);
return TRUE;
}
gboolean
dmap_mdns_publisher_set_txt_records (DmapMdnsPublisher *publisher,
gchar **txt_records,
GError **error)
{
g_return_val_if_fail (publisher != NULL, FALSE);
if (ptr == NULL) {
g_set_error (error,
DMAP_MDNS_PUBLISHER_ERROR,
DMAP_MDNS_PUBLISHER_ERROR_FAILED,
"%s",
_("No service at port"));
return FALSE;
}
publisher_set_txt_records_internal (publisher, txt_records, error);
g_free (((struct DmapMdnsPublisherService *) ptr->data)->name);
((struct DmapMdnsPublisherService *) ptr->data)->name = g_strdup (name);
if (publisher->priv->entry_group) {
refresh_service (publisher, error);
refresh_services (publisher, error);
}
return TRUE;
......@@ -337,6 +260,8 @@ dmap_mdns_publisher_publish (DmapMdnsPublisher *publisher,
gchar **txt_records,
GError **error)
{
struct DmapMdnsPublisherService *service;
if (publisher->priv->client == NULL) {
g_set_error (error,
DMAP_MDNS_PUBLISHER_ERROR,
......@@ -346,13 +271,18 @@ dmap_mdns_publisher_publish (DmapMdnsPublisher *publisher,
return FALSE;
}
publisher_set_name_internal (publisher, name, NULL);
publisher_set_port_internal (publisher, port, NULL);
publisher_set_type_of_service_internal (publisher, type_of_service, NULL);
publisher_set_password_required_internal (publisher, password_required, NULL);
publisher_set_txt_records_internal (publisher, txt_records, NULL);
service = g_new (struct DmapMdnsPublisherService, 1);
service->name = g_strdup(name);
service->port = port;
service->type_of_service = g_strdup (type_of_service);
service->password_required = password_required;
service->txt_records = g_strdupv (txt_records);
publisher->priv->service = g_slist_append (publisher->priv->service, service);
return create_service (publisher, error);
return create_services (publisher, error);
}
gboolean
......@@ -410,11 +340,30 @@ dmap_mdns_publisher_get_property (GObject *object,
}
}
static GObject *
dmap_mdns_publisher_constructor (GType type,
guint n_construct_params,
GObjectConstructParam *construct_params)
{
/* This class is a singleton. */
static GObject *self = NULL;
if (self == NULL) {
self = G_OBJECT_CLASS (dmap_mdns_publisher_parent_class)->constructor (
type, n_construct_params, construct_params);
g_object_add_weak_pointer (self, (gpointer) &self);
return self;
}
return g_object_ref (self);
}
static void
dmap_mdns_publisher_class_init (DmapMdnsPublisherClass *klass)
{
GObjectClass *object_class = G_OBJECT_CLASS (klass);
object_class->constructor = dmap_mdns_publisher_constructor;
object_class->finalize = dmap_mdns_publisher_finalize;
object_class->get_property = dmap_mdns_publisher_get_property;
object_class->set_property = dmap_mdns_publisher_set_property;
......@@ -448,7 +397,17 @@ dmap_mdns_publisher_init (DmapMdnsPublisher *publisher)
{
publisher->priv = DMAP_MDNS_PUBLISHER_GET_PRIVATE (publisher);
publisher->priv->client = dmap_mdns_avahi_get_client ();
publisher->priv->client = dmap_mdns_avahi_get_client ();
publisher->priv->entry_group = NULL;
publisher->priv->service = NULL;
}
static void
free_service (struct DmapMdnsPublisherService *service, gpointer user_data)
{
g_free (service->name);
g_free (service->type_of_service);
g_strfreev (service->txt_records);
}
static void
......@@ -470,10 +429,8 @@ dmap_mdns_publisher_finalize (GObject *object)
avahi_client_free (publisher->priv->client);
g_free (publisher->priv->name);
g_free (publisher->priv->type_of_service);
g_strfreev (publisher->priv->txt_records);
g_slist_foreach (publisher->priv->service, (GFunc) free_service, NULL);
g_slist_free (publisher->priv->service);
G_OBJECT_CLASS (dmap_mdns_publisher_parent_class)->finalize (object);
}
......
......@@ -77,18 +77,10 @@ gboolean dmap_mdns_publisher_publish (DmapMdnsPublish
gboolean password_required,
gchar **txt_records,
GError **error);
gboolean dmap_mdns_publisher_set_name (DmapMdnsPublisher *publisher,
gboolean dmap_mdns_publisher_rename_at_port (DmapMdnsPublisher *publisher,
guint port,
const char *name,
GError **error);
gboolean dmap_mdns_publisher_set_port (DmapMdnsPublisher *publisher,
guint port,
GError **error);
gboolean dmap_mdns_publisher_set_password_required (DmapMdnsPublisher *publisher,
gboolean required,
GError **error);
gboolean dmap_mdns_publisher_set_txt_records (DmapMdnsPublisher *publisher,
gchar **txt_records,
GError **error);
gboolean dmap_mdns_publisher_withdraw (DmapMdnsPublisher *publisher,
GError **error);
......
......@@ -405,14 +405,17 @@ _dmap_share_set_name (DMAPShare *share, const char *name)
g_free (share->priv->name);
share->priv->name = g_strdup (name);
error = NULL;
res = dmap_mdns_publisher_set_name (share->priv->publisher,
name,
&error);
if (error != NULL) {
g_warning ("Unable to change MDNS service name: %s",
error->message);
g_error_free (error);
if (share->priv->published) {
error = NULL;
res = dmap_mdns_publisher_rename_at_port (share->priv->publisher,
share->priv->port,
name,
&error);
if (error != NULL) {
g_warning ("Unable to change MDNS service name: %s",
error->message);
g_error_free (error);
}
}
}
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment