1
/* -*- Mode: C; tab-width: 8; indent-tabs-mode: t; c-basic-offset: 8 -*-
3
* Copyright (C) 2005 Charles Schmidt <cschmidt2@emich.edu>
4
* Copyright (C) 2006 William Jon McCann <mccann@jhu.edu>
6
* This program is free software; you can redistribute it and/or modify
7
* it under the terms of the GNU General Public License as published by
8
* the Free Software Foundation; either version 2 of the License, or
9
* (at your option) any later version.
11
* This program is distributed in the hope that it will be useful,
12
* but WITHOUT ANY WARRANTY; without even the implied warranty of
13
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14
* GNU General Public License for more details.
16
* You should have received a copy of the GNU General Public License
17
* along with this program; if not, write to the Free Software
18
* Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA.
28
#include <glib/gi18n.h>
29
#include <glib-object.h>
31
/* stupid howl includes howl_config.h */
36
#include "rb-daap-mdns-publisher.h"
39
static void rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass *klass);
40
static void rb_daap_mdns_publisher_init (RBDaapMdnsPublisher *publisher);
41
static void rb_daap_mdns_publisher_finalize (GObject *object);
43
#define RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE(o) (G_TYPE_INSTANCE_GET_PRIVATE ((o), RB_TYPE_DAAP_MDNS_PUBLISHER, RBDaapMdnsPublisherPrivate))
45
struct RBDaapMdnsPublisherPrivate
47
sw_discovery *discovery;
48
sw_discovery_oid *oid;
54
gboolean password_required;
67
static guint signals [LAST_SIGNAL] = { 0, };
69
G_DEFINE_TYPE (RBDaapMdnsPublisher, rb_daap_mdns_publisher, G_TYPE_OBJECT)
71
static gpointer publisher_object = NULL;
74
rb_daap_mdns_publisher_error_quark (void)
76
static GQuark quark = 0;
78
quark = g_quark_from_static_string ("rb_daap_mdns_publisher_error");
84
howl_in_cb (GIOChannel *io_channel,
85
GIOCondition condition,
86
RBDaapMdnsPublisher *publisher)
90
if (sw_discovery_salt (*publisher->priv->discovery, &salt) == SW_OKAY) {
92
sw_discovery_read_socket (*publisher->priv->discovery);
93
sw_salt_unlock (salt);
100
howl_client_init (RBDaapMdnsPublisher *publisher)
106
publisher->priv->discovery = g_new0 (sw_discovery, 1);
107
result = sw_discovery_init (publisher->priv->discovery);
109
if (result != SW_OKAY) {
110
g_free (publisher->priv->discovery);
111
publisher->priv->discovery = NULL;
115
fd = sw_discovery_socket (*publisher->priv->discovery);
117
channel = g_io_channel_unix_new (fd);
118
publisher->priv->watch_id = g_io_add_watch (channel, G_IO_IN, (GIOFunc)howl_in_cb, publisher);
119
g_io_channel_unref (channel);
123
publish_cb (sw_discovery discovery,
124
sw_discovery_oid oid,
125
sw_discovery_publish_status status,
126
RBDaapMdnsPublisher *publisher)
128
if (status == SW_DISCOVERY_PUBLISH_STARTED) {
129
g_signal_emit (publisher, signals [PUBLISHED], 0, publisher->priv->name);
130
} else if (status == SW_DISCOVERY_PUBLISH_NAME_COLLISION) {
131
/* This is all well and good, but howl won't report a name collision.
132
* http://lists.porchdogsoft.com/pipermail/howl-users/Week-of-Mon-20041206/000487.html
135
g_warning ("MDNS name collision");
137
g_signal_emit (publisher, signals [NAME_COLLISION], 0, publisher->priv->name);
144
howl_strerror (sw_result result)
151
case SW_DISCOVERY_E_NO_MEM:
152
str = "Out of memory";
153
case SW_DISCOVERY_E_BAD_PARAM:
154
str = "Invalid paramater";
155
case SW_DISCOVERY_E_UNKNOWN:
157
str = "Unknown error";
164
create_service (RBDaapMdnsPublisher *publisher,
167
sw_text_record text_record;
170
if (sw_text_record_init (&text_record) != SW_OKAY) {
171
rb_debug ("Error initializing Howl text record");
173
RB_DAAP_MDNS_PUBLISHER_ERROR,
174
RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
176
_("Error initializing Howl for publishing"));
180
if (publisher->priv->oid != NULL) {
181
rb_daap_mdns_publisher_withdraw (publisher, NULL);
184
publisher->priv->oid = g_new0 (sw_discovery_oid, 1);
186
sw_text_record_add_key_and_string_value (text_record,
188
publisher->priv->password_required ? "true" : "false");
190
result = sw_discovery_publish (*publisher->priv->discovery,
192
publisher->priv->name,
196
publisher->priv->port,
197
sw_text_record_bytes (text_record),
198
sw_text_record_len (text_record),
199
(sw_discovery_publish_reply) publish_cb,
200
(sw_opaque) publisher,
201
(sw_discovery_oid *) publisher->priv->oid);
203
sw_text_record_fina (text_record);
205
if (result != SW_OKAY) {
206
rb_debug ("Error starting mDNS publish with Howl: %s", howl_strerror (result));
208
RB_DAAP_MDNS_PUBLISHER_ERROR,
209
RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
211
_("Error initializing Howl for publishing"),
212
howl_strerror (result));
220
refresh_service (RBDaapMdnsPublisher *publisher,
223
return create_service (publisher, error);
227
rb_daap_mdns_publisher_publish (RBDaapMdnsPublisher *publisher,
230
gboolean password_required,
233
if (publisher->priv->discovery == NULL) {
235
RB_DAAP_MDNS_PUBLISHER_ERROR,
236
RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING,
238
_("The howl MDNS service is not running"));
242
rb_daap_mdns_publisher_set_name (publisher, name, NULL);
243
rb_daap_mdns_publisher_set_port (publisher, port, NULL);
244
rb_daap_mdns_publisher_set_password_required (publisher, password_required, NULL);
246
/* special case: the _set_ functions have updated the existing entry group */
247
if (publisher->priv->oid != NULL) {
251
return create_service (publisher, error);
255
rb_daap_mdns_publisher_withdraw (RBDaapMdnsPublisher *publisher,
258
if (publisher->priv->discovery == NULL) {
260
RB_DAAP_MDNS_PUBLISHER_ERROR,
261
RB_DAAP_MDNS_PUBLISHER_ERROR_NOT_RUNNING,
263
_("The howl MDNS service is not running"));
267
if (publisher->priv->oid == NULL) {
269
RB_DAAP_MDNS_PUBLISHER_ERROR,
270
RB_DAAP_MDNS_PUBLISHER_ERROR_FAILED,
272
_("The MDNS service is not published"));
276
sw_discovery_cancel (*publisher->priv->discovery, *publisher->priv->oid);
278
g_free (publisher->priv->oid);
279
publisher->priv->oid = NULL;
285
rb_daap_mdns_publisher_set_name (RBDaapMdnsPublisher *publisher,
289
g_return_val_if_fail (publisher != NULL, FALSE);
291
g_free (publisher->priv->name);
292
publisher->priv->name = g_strdup (name);
294
if (publisher->priv->oid) {
295
refresh_service (publisher, error);
301
rb_daap_mdns_publisher_set_port (RBDaapMdnsPublisher *publisher,
305
g_return_val_if_fail (publisher != NULL, FALSE);
307
publisher->priv->port = port;
309
if (publisher->priv->oid) {
310
refresh_service (publisher, error);
316
rb_daap_mdns_publisher_set_password_required (RBDaapMdnsPublisher *publisher,
320
g_return_val_if_fail (publisher != NULL, FALSE);
322
publisher->priv->password_required = required;
324
if (publisher->priv->oid) {
325
refresh_service (publisher, error);
332
rb_daap_mdns_publisher_set_property (GObject *object,
339
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
345
rb_daap_mdns_publisher_get_property (GObject *object,
352
G_OBJECT_WARN_INVALID_PROPERTY_ID (object, prop_id, pspec);
358
rb_daap_mdns_publisher_class_init (RBDaapMdnsPublisherClass *klass)
360
GObjectClass *object_class = G_OBJECT_CLASS (klass);
362
object_class->finalize = rb_daap_mdns_publisher_finalize;
363
object_class->get_property = rb_daap_mdns_publisher_get_property;
364
object_class->set_property = rb_daap_mdns_publisher_set_property;
366
signals [PUBLISHED] =
367
g_signal_new ("published",
368
G_TYPE_FROM_CLASS (object_class),
370
G_STRUCT_OFFSET (RBDaapMdnsPublisherClass, published),
373
g_cclosure_marshal_VOID__STRING,
376
signals [NAME_COLLISION] =
377
g_signal_new ("name-collision",
378
G_TYPE_FROM_CLASS (object_class),
380
G_STRUCT_OFFSET (RBDaapMdnsPublisherClass, name_collision),
383
g_cclosure_marshal_VOID__STRING,
387
g_type_class_add_private (klass, sizeof (RBDaapMdnsPublisherPrivate));
391
rb_daap_mdns_publisher_init (RBDaapMdnsPublisher *publisher)
393
publisher->priv = RB_DAAP_MDNS_PUBLISHER_GET_PRIVATE (publisher);
395
howl_client_init (publisher);
399
rb_daap_mdns_publisher_finalize (GObject *object)
401
RBDaapMdnsPublisher *publisher;
403
g_return_if_fail (object != NULL);
404
g_return_if_fail (RB_IS_DAAP_MDNS_PUBLISHER (object));
406
publisher = RB_DAAP_MDNS_PUBLISHER (object);
408
g_return_if_fail (publisher->priv != NULL);
410
if (publisher->priv->oid) {
411
rb_daap_mdns_publisher_withdraw (publisher, NULL);
414
if (publisher->priv->discovery) {
415
sw_discovery_fina (*publisher->priv->discovery);
416
g_free (publisher->priv->discovery);
419
if (publisher->priv->watch_id > 0) {
420
g_source_remove (publisher->priv->watch_id);
423
g_free (publisher->priv->name);
425
G_OBJECT_CLASS (rb_daap_mdns_publisher_parent_class)->finalize (object);
428
RBDaapMdnsPublisher *
429
rb_daap_mdns_publisher_new (void)
431
if (publisher_object) {
432
g_object_ref (publisher_object);
434
publisher_object = g_object_new (RB_TYPE_DAAP_MDNS_PUBLISHER, NULL);
435
g_object_add_weak_pointer (publisher_object,
436
(gpointer *) &publisher_object);
439
return RB_DAAP_MDNS_PUBLISHER (publisher_object);