62 typedef struct xmms_ipc_client_St {
82 static GMutex *ipc_servers_lock;
83 static GList *ipc_servers = NULL;
85 static GMutex *ipc_object_pool_lock;
101 if (argument_list &&
xmmsv_list_get (argument_list, i, &arg_value)) {
109 if (actual_type != expected_type) {
110 XMMS_DBG (
"Expected type %i, but got type %i",
111 expected_type, actual_type);
117 arg->
values[i] = arg_value;
127 xmms_log_error (
"Failed to serialize the return value into the IPC message!");
156 g_mutex_lock (client->lock);
158 g_mutex_unlock (client->lock);
186 g_mutex_lock (client->lock);
187 client->broadcasts[broadcastid] =
188 g_list_append (client->broadcasts[broadcastid],
191 g_mutex_unlock (client->lock);
202 uint32_t objid, cmdid;
205 g_return_if_fail (msg);
212 "Ignoring command.");
219 xmms_ipc_register_signal (client, msg, arguments);
221 xmms_ipc_register_broadcast (client, msg, arguments);
234 g_mutex_lock (ipc_object_pool_lock);
235 object = ipc_object_pool->objects[objid];
236 g_mutex_unlock (ipc_object_pool_lock);
243 cmd = g_tree_lookup (object->
cmds, GUINT_TO_POINTER (cmdid));
253 if (!type_and_msg_to_arg (cmd->
args[i], arguments, &arg, i)) {
259 "Maybe the client or libxmmsclient " 260 "needs to be updated.");
277 xmms_ipc_handle_cmd_value (retmsg, arg.
retval);
304 g_mutex_lock (client->lock);
305 xmms_ipc_client_msg_write (client, retmsg);
306 g_mutex_unlock (client->lock);
316 xmms_ipc_client_read_cb (GIOChannel *iochan,
321 bool disconnect = FALSE;
323 g_return_val_if_fail (client, FALSE);
325 if (cond & G_IO_IN) {
327 if (!client->read_msg) {
333 client->read_msg = NULL;
334 process_msg (client, msg);
342 if (disconnect || (cond & G_IO_HUP)) {
343 if (client->read_msg) {
345 client->read_msg = NULL;
348 g_main_loop_quit (client->ml);
352 if (cond & G_IO_ERR) {
354 g_main_loop_quit (client->ml);
362 xmms_ipc_client_write_cb (GIOChannel *iochan,
367 bool disconnect = FALSE;
369 g_return_val_if_fail (client, FALSE);
374 g_mutex_lock (client->lock);
375 msg = g_queue_peek_head (client->out_msg);
376 g_mutex_unlock (client->lock);
392 g_mutex_lock (client->lock);
393 g_queue_pop_head (client->out_msg);
394 g_mutex_unlock (client->lock);
403 xmms_ipc_client_thread (gpointer data)
408 source = g_io_create_watch (client->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP);
409 g_source_set_callback (source,
410 (GSourceFunc) xmms_ipc_client_read_cb,
413 g_source_attach (source, g_main_loop_get_context (client->ml));
414 g_source_unref (source);
416 g_main_loop_run (client->ml);
418 xmms_ipc_client_destroy (client);
427 GMainContext *context;
430 g_return_val_if_fail (transport, NULL);
434 context = g_main_context_new ();
435 client->ml = g_main_loop_new (context, FALSE);
436 g_main_context_unref (context);
439 client->iochan = g_io_channel_unix_new (fd);
440 g_return_val_if_fail (client->iochan, NULL);
445 g_io_channel_set_encoding (client->iochan, NULL, NULL);
446 g_io_channel_set_buffered (client->iochan, FALSE);
448 client->transport = transport;
450 client->out_msg = g_queue_new ();
451 client->lock = g_mutex_new ();
464 g_mutex_lock (client->ipc->mutex_lock);
465 client->ipc->clients = g_list_remove (client->ipc->clients, client);
466 g_mutex_unlock (client->ipc->mutex_lock);
469 g_main_loop_unref (client->ml);
470 g_io_channel_unref (client->iochan);
474 g_mutex_lock (client->lock);
475 while (!g_queue_is_empty (client->out_msg)) {
480 g_queue_free (client->out_msg);
483 g_list_free (client->broadcasts[i]);
486 g_mutex_unlock (client->lock);
487 g_mutex_free (client->lock);
499 XMMS_DBG (
"Shutting down ipc server threads through config property \"core.ipcsocket\" change.");
513 gboolean queue_empty;
515 g_return_val_if_fail (client, FALSE);
516 g_return_val_if_fail (msg, FALSE);
518 queue_empty = g_queue_is_empty (client->out_msg);
519 g_queue_push_tail (client->out_msg, msg);
523 GMainContext *context = g_main_loop_get_context (client->ml);
524 GSource *source = g_io_create_watch (client->iochan, G_IO_OUT);
526 g_source_set_callback (source,
527 (GSourceFunc) xmms_ipc_client_write_cb,
530 g_source_attach (source, context);
531 g_source_unref (source);
533 g_main_context_wakeup (context);
540 xmms_ipc_source_accept (GIOChannel *chan, GIOCondition cond, gpointer data)
546 if (!(cond & G_IO_IN)) {
558 client = xmms_ipc_client_new (ipc, transport);
564 g_mutex_lock (ipc->mutex_lock);
565 ipc->clients = g_list_append (ipc->clients, client);
566 g_mutex_unlock (ipc->mutex_lock);
571 g_thread_create (xmms_ipc_client_thread, client, FALSE, NULL);
580 xmms_ipc_setup_server_internaly (
xmms_ipc_t *ipc)
582 g_mutex_lock (ipc->mutex_lock);
585 g_io_channel_set_close_on_unref (ipc->chan, TRUE);
586 g_io_channel_set_encoding (ipc->chan, NULL, NULL);
587 g_io_channel_set_buffered (ipc->chan, FALSE);
589 g_io_add_watch (ipc->chan, G_IO_IN | G_IO_HUP | G_IO_ERR,
590 xmms_ipc_source_accept, ipc);
591 g_mutex_unlock (ipc->mutex_lock);
604 g_mutex_lock (ipc_servers_lock);
606 for (s = ipc_servers; s; s = g_list_next (s)) {
608 g_mutex_lock (ipc->mutex_lock);
609 for (c = ipc->clients; c; c = g_list_next (c)) {
611 g_mutex_lock (cli->lock);
612 if (cli->pendingsignals[signalid]) {
613 g_mutex_unlock (cli->lock);
614 g_mutex_unlock (ipc->mutex_lock);
615 g_mutex_unlock (ipc_servers_lock);
618 g_mutex_unlock (cli->lock);
620 g_mutex_unlock (ipc->mutex_lock);
623 g_mutex_unlock (ipc_servers_lock);
631 guint signalid = GPOINTER_TO_UINT (userdata);
635 g_mutex_lock (ipc_servers_lock);
637 for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
639 g_mutex_lock (ipc->mutex_lock);
640 for (c = ipc->clients; c; c = g_list_next (c)) {
642 g_mutex_lock (cli->lock);
643 if (cli->pendingsignals[signalid]) {
646 xmms_ipc_handle_cmd_value (msg, arg);
647 xmms_ipc_client_msg_write (cli, msg);
648 cli->pendingsignals[signalid] = 0;
650 g_mutex_unlock (cli->lock);
652 g_mutex_unlock (ipc->mutex_lock);
655 g_mutex_unlock (ipc_servers_lock);
663 guint broadcastid = GPOINTER_TO_UINT (userdata);
668 g_mutex_lock (ipc_servers_lock);
670 for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
672 g_mutex_lock (ipc->mutex_lock);
673 for (c = ipc->clients; c; c = g_list_next (c)) {
676 g_mutex_lock (cli->lock);
677 for (l = cli->broadcasts[broadcastid]; l; l = g_list_next (l)) {
680 xmms_ipc_handle_cmd_value (msg, arg);
681 xmms_ipc_client_msg_write (cli, msg);
683 g_mutex_unlock (cli->lock);
685 g_mutex_unlock (ipc->mutex_lock);
687 g_mutex_unlock (ipc_servers_lock);
696 g_return_if_fail (
object);
697 g_mutex_lock (ipc_object_pool_lock);
699 ipc_object_pool->broadcasts[signalid] = object;
700 xmms_object_connect (
object, signalid, xmms_ipc_broadcast_cb, GUINT_TO_POINTER (signalid));
702 g_mutex_unlock (ipc_object_pool_lock);
713 g_mutex_lock (ipc_object_pool_lock);
714 obj = ipc_object_pool->broadcasts[signalid];
717 ipc_object_pool->broadcasts[signalid] = NULL;
719 g_mutex_unlock (ipc_object_pool_lock);
728 g_return_if_fail (
object);
730 g_mutex_lock (ipc_object_pool_lock);
731 ipc_object_pool->signals[signalid] = object;
733 g_mutex_unlock (ipc_object_pool_lock);
744 g_mutex_lock (ipc_object_pool_lock);
745 obj = ipc_object_pool->signals[signalid];
748 ipc_object_pool->signals[signalid] = NULL;
750 g_mutex_unlock (ipc_object_pool_lock);
760 g_mutex_lock (ipc_object_pool_lock);
761 ipc_object_pool->objects[objectid] = object;
762 g_mutex_unlock (ipc_object_pool_lock);
771 g_mutex_lock (ipc_object_pool_lock);
772 ipc_object_pool->objects[objectid] = NULL;
773 g_mutex_unlock (ipc_object_pool_lock);
782 ipc_servers_lock = g_mutex_new ();
783 ipc_object_pool_lock = g_mutex_new ();
798 g_mutex_lock (ipc->mutex_lock);
799 g_source_remove_by_user_data (ipc);
800 g_io_channel_unref (ipc->chan);
803 for (c = ipc->clients; c; c = g_list_next (c)) {
809 g_list_free (ipc->clients);
810 g_mutex_unlock (ipc->mutex_lock);
811 g_mutex_free (ipc->mutex_lock);
824 GList *s = ipc_servers;
827 g_mutex_lock (ipc_servers_lock);
831 ipc_servers = g_list_remove (ipc_servers, ipc);
832 xmms_ipc_shutdown_server (ipc);
834 g_mutex_unlock (ipc_servers_lock);
847 gint i = 0, num_init = 0;
848 g_return_val_if_fail (path, FALSE);
850 split = g_strsplit (path,
";", 0);
852 for (i = 0; split && split[i]; i++) {
855 XMMS_DBG (
"No IPC server initialized.");
862 xmms_log_error (
"Couldn't setup IPC listening on '%s'.", split[i]);
867 ipc->mutex_lock = g_mutex_new ();
868 ipc->transport = transport;
869 ipc->signals = ipc_object_pool->signals;
870 ipc->broadcasts = ipc_object_pool->broadcasts;
871 ipc->objects = ipc_object_pool->objects;
873 xmms_ipc_setup_server_internaly (ipc);
876 g_mutex_lock (ipc_servers_lock);
877 ipc_servers = g_list_prepend (ipc_servers, ipc);
878 g_mutex_unlock (ipc_servers_lock);
#define xmms_error_isok(e)
xmms_ipc_t * xmms_ipc_init(void)
Initialize IPC.
void xmms_ipc_msg_set_cookie(xmms_ipc_msg_t *msg, uint32_t cookie)
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed...
xmms_ipc_msg_t * xmms_ipc_msg_alloc(void)
xmms_socket_t xmms_ipc_transport_fd_get(xmms_ipc_transport_t *ipct)
int xmmsv_list_get(xmmsv_t *listv, int pos, xmmsv_t **val)
Get the element at the given position in the list xmmsv_t.
void on_config_ipcsocket_change(xmms_object_t *object, xmmsv_t *_data, gpointer udata)
Gets called when the config property "core.ipcsocket" has changed.
gboolean xmms_ipc_has_pending(guint signalid)
Checks if someone is waiting for signalid.
xmmsv_t * xmmsv_new_error(const char *errstr)
Allocates a new error xmmsv_t.
xmmsv_type_t args[XMMS_OBJECT_CMD_MAX_ARGS]
bool xmms_ipc_msg_get_value(xmms_ipc_msg_t *msg, xmmsv_t **val)
xmmsv_t * xmmsv_new_none(void)
Allocates a new empty xmmsv_t.
uint32_t xmms_ipc_msg_get_cmd(const xmms_ipc_msg_t *msg)
void xmms_ipc_broadcast_register(xmms_object_t *object, xmms_ipc_signals_t signalid)
Register a broadcast signal.
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
gboolean xmms_ipc_setup_server(const gchar *path)
Start the server.
void xmms_ipc_signal_register(xmms_object_t *object, xmms_ipc_signals_t signalid)
Register a signal.
const gchar * xmms_error_message_get(xmms_error_t *err)
Get the human readable error.
void xmms_ipc_msg_destroy(xmms_ipc_msg_t *msg)
struct xmms_ipc_msg_St xmms_ipc_msg_t
struct xmms_ipc_client_St xmms_ipc_client_t
A IPC client representation.
xmms_ipc_msg_t * xmms_ipc_msg_new(uint32_t object, uint32_t cmd)
#define xmms_log_error(fmt,...)
void xmms_object_cmd_arg_init(xmms_object_cmd_arg_t *arg)
Initialize a command argument.
bool xmms_ipc_msg_write_transport(xmms_ipc_msg_t *msg, xmms_ipc_transport_t *transport, bool *disconnected)
Try to write message to transport.
void xmms_object_cmd_call(xmms_object_t *object, guint cmdid, xmms_object_cmd_arg_t *arg)
Call a command with argument.
struct xmms_ipc_object_pool_t xmms_ipc_object_pool_t
The IPC object list.
xmms_ipc_transport_t * xmms_ipc_server_init(const char *path)
const gchar * xmms_config_property_get_string(const xmms_config_property_t *prop)
Return the value of a config property as a string.
void xmms_ipc_signal_unregister(xmms_ipc_signals_t signalid)
Unregister a signal.
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
void xmms_ipc_object_unregister(xmms_ipc_objects_t objectid)
Remove a object from the IPC core.
xmmsv_t * xmmsv_ref(xmmsv_t *val)
References the xmmsv_t.
xmms_ipc_transport_t * xmms_ipc_server_accept(xmms_ipc_transport_t *ipct)
uint32_t xmms_ipc_msg_put_value(xmms_ipc_msg_t *msg, xmmsv_t *v)
#define xmms_log_info(fmt,...)
bool xmms_ipc_msg_read_transport(xmms_ipc_msg_t *msg, xmms_ipc_transport_t *transport, bool *disconnected)
Try to read message from transport into msg.
uint32_t xmms_ipc_msg_get_object(const xmms_ipc_msg_t *msg)
void xmms_ipc_shutdown(void)
Disable IPC.
#define XMMS_DBG(fmt,...)
void xmms_object_connect(xmms_object_t *object, guint32 signalid, xmms_object_handler_t handler, gpointer userdata)
Connect to a signal that is emitted by this object.
struct xmms_ipc_St xmms_ipc_t
void xmms_ipc_broadcast_unregister(xmms_ipc_signals_t signalid)
Unregister a broadcast signal.
void xmms_object_disconnect(xmms_object_t *object, guint32 signalid, xmms_object_handler_t handler, gpointer userdata)
Disconnect from a signal.
xmmsv_t * values[XMMS_OBJECT_CMD_MAX_ARGS]
struct xmms_config_property_St xmms_config_property_t
void xmms_ipc_object_register(xmms_ipc_objects_t objectid, xmms_object_t *object)
Register a object to the IPC core.
void xmms_ipc_transport_destroy(xmms_ipc_transport_t *ipct)
uint32_t xmms_ipc_msg_get_cookie(const xmms_ipc_msg_t *msg)
#define XMMS_OBJECT_CMD_MAX_ARGS