XMMS2
src/xmms/ipc.c
Go to the documentation of this file.
00001 /*  XMMS2 - X Music Multiplexer System
00002  *  Copyright (C) 2003-2011 XMMS2 Team
00003  *
00004  *  PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
00005  *
00006  *  This library is free software; you can redistribute it and/or
00007  *  modify it under the terms of the GNU Lesser General Public
00008  *  License as published by the Free Software Foundation; either
00009  *  version 2.1 of the License, or (at your option) any later version.
00010  *
00011  *  This library is distributed in the hope that it will be useful,
00012  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
00013  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
00014  *  Lesser General Public License for more details.
00015  */
00016 
00017 #include <glib.h>
00018 #include <string.h>
00019 
00020 #include "xmms/xmms_log.h"
00021 #include "xmms/xmms_config.h"
00022 #include "xmmspriv/xmms_thread_name.h"
00023 #include "xmmspriv/xmms_ipc.h"
00024 #include "xmmsc/xmmsc_ipc_msg.h"
00025 
00026 
00027 /**
00028   * @defgroup IPC IPC
00029   * @ingroup XMMSServer
00030   * @brief IPC functions for XMMS2 Daemon
00031   * @{
00032   */
00033 
00034 
00035 
00036 /**
00037  * The IPC object list
00038  */
00039 typedef struct xmms_ipc_object_pool_t {
00040     xmms_object_t *objects[XMMS_IPC_OBJECT_END];
00041     xmms_object_t *signals[XMMS_IPC_SIGNAL_END];
00042     xmms_object_t *broadcasts[XMMS_IPC_SIGNAL_END];
00043 } xmms_ipc_object_pool_t;
00044 
00045 
00046 /**
00047  * The server IPC object
00048  */
00049 struct xmms_ipc_St {
00050     xmms_ipc_transport_t *transport;
00051     GList *clients;
00052     GIOChannel *chan;
00053     GMutex *mutex_lock;
00054     xmms_object_t **objects;
00055     xmms_object_t **signals;
00056     xmms_object_t **broadcasts;
00057 };
00058 
00059 
00060 /**
00061  * A IPC client representation.
00062  */
00063 typedef struct xmms_ipc_client_St {
00064     GMainLoop *ml;
00065     GIOChannel *iochan;
00066 
00067     xmms_ipc_transport_t *transport;
00068     xmms_ipc_msg_t *read_msg;
00069     xmms_ipc_t *ipc;
00070 
00071     /* this lock protects out_msg, pendingsignals and broadcasts,
00072        which can be accessed from other threads than the
00073        client-thread */
00074     GMutex *lock;
00075 
00076     /** Messages waiting to be written */
00077     GQueue *out_msg;
00078 
00079     guint pendingsignals[XMMS_IPC_SIGNAL_END];
00080     GList *broadcasts[XMMS_IPC_SIGNAL_END];
00081 } xmms_ipc_client_t;
00082 
00083 static GMutex *ipc_servers_lock;
00084 static GList *ipc_servers = NULL;
00085 
00086 static GMutex *ipc_object_pool_lock;
00087 static struct xmms_ipc_object_pool_t *ipc_object_pool = NULL;
00088 
00089 static void xmms_ipc_client_destroy (xmms_ipc_client_t *client);
00090 
00091 static void xmms_ipc_register_signal (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg, xmmsv_t *arguments);
00092 static void xmms_ipc_register_broadcast (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg, xmmsv_t *arguments);
00093 static gboolean xmms_ipc_client_msg_write (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg);
00094 
00095 static void
00096 xmms_ipc_handle_cmd_value (xmms_ipc_msg_t *msg, xmmsv_t *val)
00097 {
00098     if (xmms_ipc_msg_put_value (msg, val) == (uint32_t) -1) {
00099         xmms_log_error ("Failed to serialize the return value into the IPC message!");
00100     }
00101 }
00102 
00103 static void
00104 xmms_ipc_register_signal (xmms_ipc_client_t *client,
00105                           xmms_ipc_msg_t *msg, xmmsv_t *arguments)
00106 {
00107     xmmsv_t *arg;
00108     gint32 signalid;
00109     int r;
00110 
00111     if (!arguments || !xmmsv_list_get (arguments, 0, &arg)) {
00112         xmms_log_error ("No signalid in this msg?!");
00113         return;
00114     }
00115 
00116     r = xmmsv_get_int (arg, &signalid);
00117 
00118     if (!r) {
00119         xmms_log_error ("Cannot extract signal id from value");
00120         return;
00121     }
00122 
00123     if (signalid < 0 || signalid >= XMMS_IPC_SIGNAL_END) {
00124         xmms_log_error ("Bad signal id (%d)", signalid);
00125         return;
00126     }
00127 
00128     g_mutex_lock (client->lock);
00129     client->pendingsignals[signalid] = xmms_ipc_msg_get_cookie (msg);
00130     g_mutex_unlock (client->lock);
00131 }
00132 
00133 static void
00134 xmms_ipc_register_broadcast (xmms_ipc_client_t *client,
00135                              xmms_ipc_msg_t *msg, xmmsv_t *arguments)
00136 {
00137     xmmsv_t *arg;
00138     gint32 broadcastid;
00139     int r;
00140 
00141     if (!arguments || !xmmsv_list_get (arguments, 0, &arg)) {
00142         xmms_log_error ("No broadcastid in this msg?!");
00143         return;
00144     }
00145 
00146     r = xmmsv_get_int (arg, &broadcastid);
00147 
00148     if (!r) {
00149         xmms_log_error ("Cannot extract broadcast id from value");
00150         return;
00151     }
00152 
00153     if (broadcastid < 0 || broadcastid >= XMMS_IPC_SIGNAL_END) {
00154         xmms_log_error ("Bad broadcast id (%d)", broadcastid);
00155         return;
00156     }
00157 
00158     g_mutex_lock (client->lock);
00159     client->broadcasts[broadcastid] =
00160         g_list_append (client->broadcasts[broadcastid],
00161                 GUINT_TO_POINTER (xmms_ipc_msg_get_cookie (msg)));
00162 
00163     g_mutex_unlock (client->lock);
00164 }
00165 
00166 static void
00167 process_msg (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg)
00168 {
00169     xmms_object_t *object;
00170     xmms_object_cmd_arg_t arg;
00171     xmms_ipc_msg_t *retmsg;
00172     xmmsv_t *error, *arguments;
00173     uint32_t objid, cmdid;
00174 
00175     g_return_if_fail (msg);
00176 
00177     objid = xmms_ipc_msg_get_object (msg);
00178     cmdid = xmms_ipc_msg_get_cmd (msg);
00179 
00180     if (!xmms_ipc_msg_get_value (msg, &arguments)) {
00181         xmms_log_error ("Cannot read command arguments. "
00182                         "Ignoring command.");
00183 
00184         return;
00185     }
00186 
00187     if (objid == XMMS_IPC_OBJECT_SIGNAL) {
00188         if (cmdid == XMMS_IPC_CMD_SIGNAL) {
00189             xmms_ipc_register_signal (client, msg, arguments);
00190         } else if (cmdid == XMMS_IPC_CMD_BROADCAST) {
00191             xmms_ipc_register_broadcast (client, msg, arguments);
00192         } else {
00193             xmms_log_error ("Bad command id (%d) for signal object", cmdid);
00194         }
00195 
00196         goto out;
00197     }
00198 
00199     if (objid >= XMMS_IPC_OBJECT_END) {
00200         xmms_log_error ("Bad object id (%d)", objid);
00201         goto out;
00202     }
00203 
00204     g_mutex_lock (ipc_object_pool_lock);
00205     object = ipc_object_pool->objects[objid];
00206     g_mutex_unlock (ipc_object_pool_lock);
00207     if (!object) {
00208         xmms_log_error ("Object %d was not found!", objid);
00209         goto out;
00210     }
00211 
00212     if (!g_tree_lookup (object->cmds, GUINT_TO_POINTER (cmdid))) {
00213         xmms_log_error ("No such cmd %d on object %d", cmdid, objid);
00214         goto out;
00215     }
00216 
00217     xmms_object_cmd_arg_init (&arg);
00218     arg.args = arguments;
00219 
00220     xmms_object_cmd_call (object, cmdid, &arg);
00221     if (xmms_error_isok (&arg.error)) {
00222         retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_REPLY);
00223         xmms_ipc_handle_cmd_value (retmsg, arg.retval);
00224     } else {
00225         /* FIXME: or we could omit setting the command to _CMD_ERROR
00226          * and let the client check whether the value it got is an
00227          * error xmmsv_t. If so, don't forget to
00228          * update the client-side of IPC too. */
00229         retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_ERROR);
00230 
00231         error = xmmsv_new_error (xmms_error_message_get (&arg.error));
00232         xmms_ipc_msg_put_value (retmsg, error);
00233         xmmsv_unref (error);
00234 
00235 /*
00236         retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_REPLY);
00237         xmms_ipc_handle_cmd_value (retmsg, arg.retval);
00238 */
00239     }
00240 
00241     if (arg.retval)
00242         xmmsv_unref (arg.retval);
00243 
00244     xmms_ipc_msg_set_cookie (retmsg, xmms_ipc_msg_get_cookie (msg));
00245     g_mutex_lock (client->lock);
00246     xmms_ipc_client_msg_write (client, retmsg);
00247     g_mutex_unlock (client->lock);
00248 
00249 out:
00250     if (arguments) {
00251         xmmsv_unref (arguments);
00252     }
00253 }
00254 
00255 
00256 static gboolean
00257 xmms_ipc_client_read_cb (GIOChannel *iochan,
00258                          GIOCondition cond,
00259                          gpointer data)
00260 {
00261     xmms_ipc_client_t *client = data;
00262     bool disconnect = FALSE;
00263 
00264     g_return_val_if_fail (client, FALSE);
00265 
00266     if (cond & G_IO_IN) {
00267         while (TRUE) {
00268             if (!client->read_msg) {
00269                 client->read_msg = xmms_ipc_msg_alloc ();
00270             }
00271 
00272             if (xmms_ipc_msg_read_transport (client->read_msg, client->transport, &disconnect)) {
00273                 xmms_ipc_msg_t *msg = client->read_msg;
00274                 client->read_msg = NULL;
00275                 process_msg (client, msg);
00276                 xmms_ipc_msg_destroy (msg);
00277             } else {
00278                 break;
00279             }
00280         }
00281     }
00282 
00283     if (disconnect || (cond & G_IO_HUP)) {
00284         if (client->read_msg) {
00285             xmms_ipc_msg_destroy (client->read_msg);
00286             client->read_msg = NULL;
00287         }
00288         XMMS_DBG ("disconnect was true!");
00289         g_main_loop_quit (client->ml);
00290         return FALSE;
00291     }
00292 
00293     if (cond & G_IO_ERR) {
00294         xmms_log_error ("Client got error, maybe connection died?");
00295         g_main_loop_quit (client->ml);
00296         return FALSE;
00297     }
00298 
00299     return TRUE;
00300 }
00301 
00302 static gboolean
00303 xmms_ipc_client_write_cb (GIOChannel *iochan,
00304                           GIOCondition cond,
00305                           gpointer data)
00306 {
00307     xmms_ipc_client_t *client = data;
00308     bool disconnect = FALSE;
00309 
00310     g_return_val_if_fail (client, FALSE);
00311 
00312     while (TRUE) {
00313         xmms_ipc_msg_t *msg;
00314 
00315         g_mutex_lock (client->lock);
00316         msg = g_queue_peek_head (client->out_msg);
00317         g_mutex_unlock (client->lock);
00318 
00319         if (!msg)
00320             break;
00321 
00322         if (!xmms_ipc_msg_write_transport (msg,
00323                                            client->transport,
00324                                            &disconnect)) {
00325             if (disconnect) {
00326                 break;
00327             } else {
00328                 /* try sending again later */
00329                 return TRUE;
00330             }
00331         }
00332 
00333         g_mutex_lock (client->lock);
00334         g_queue_pop_head (client->out_msg);
00335         g_mutex_unlock (client->lock);
00336 
00337         xmms_ipc_msg_destroy (msg);
00338     }
00339 
00340     return FALSE;
00341 }
00342 
00343 static gpointer
00344 xmms_ipc_client_thread (gpointer data)
00345 {
00346     xmms_ipc_client_t *client = data;
00347     GSource *source;
00348 
00349     xmms_set_thread_name ("x2 client");
00350 
00351     source = g_io_create_watch (client->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP);
00352     g_source_set_callback (source,
00353                            (GSourceFunc) xmms_ipc_client_read_cb,
00354                            (gpointer) client,
00355                            NULL);
00356     g_source_attach (source, g_main_loop_get_context (client->ml));
00357     g_source_unref (source);
00358 
00359     g_main_loop_run (client->ml);
00360 
00361     xmms_ipc_client_destroy (client);
00362 
00363     return NULL;
00364 }
00365 
00366 static xmms_ipc_client_t *
00367 xmms_ipc_client_new (xmms_ipc_t *ipc, xmms_ipc_transport_t *transport)
00368 {
00369     xmms_ipc_client_t *client;
00370     GMainContext *context;
00371     int fd;
00372 
00373     g_return_val_if_fail (transport, NULL);
00374 
00375     client = g_new0 (xmms_ipc_client_t, 1);
00376 
00377     context = g_main_context_new ();
00378     client->ml = g_main_loop_new (context, FALSE);
00379     g_main_context_unref (context);
00380 
00381     fd = xmms_ipc_transport_fd_get (transport);
00382     client->iochan = g_io_channel_unix_new (fd);
00383     g_return_val_if_fail (client->iochan, NULL);
00384 
00385     /* We don't set the close_on_unref flag here, because
00386      * the transport will close the fd for us. No need to close it twice.
00387      */
00388     g_io_channel_set_encoding (client->iochan, NULL, NULL);
00389     g_io_channel_set_buffered (client->iochan, FALSE);
00390 
00391     client->transport = transport;
00392     client->ipc = ipc;
00393     client->out_msg = g_queue_new ();
00394     client->lock = g_mutex_new ();
00395 
00396     return client;
00397 }
00398 
00399 static void
00400 xmms_ipc_client_destroy (xmms_ipc_client_t *client)
00401 {
00402     guint i;
00403 
00404     XMMS_DBG ("Destroying client!");
00405 
00406     if (client->ipc) {
00407         g_mutex_lock (client->ipc->mutex_lock);
00408         client->ipc->clients = g_list_remove (client->ipc->clients, client);
00409         g_mutex_unlock (client->ipc->mutex_lock);
00410     }
00411 
00412     g_main_loop_unref (client->ml);
00413     g_io_channel_unref (client->iochan);
00414 
00415     xmms_ipc_transport_destroy (client->transport);
00416 
00417     g_mutex_lock (client->lock);
00418     while (!g_queue_is_empty (client->out_msg)) {
00419         xmms_ipc_msg_t *msg = g_queue_pop_head (client->out_msg);
00420         xmms_ipc_msg_destroy (msg);
00421     }
00422 
00423     g_queue_free (client->out_msg);
00424 
00425     for (i = 0; i < XMMS_IPC_SIGNAL_END; i++) {
00426         g_list_free (client->broadcasts[i]);
00427     }
00428 
00429     g_mutex_unlock (client->lock);
00430     g_mutex_free (client->lock);
00431     g_free (client);
00432 }
00433 
00434 /**
00435  * Gets called when the config property "core.ipcsocket" has changed.
00436  */
00437 void
00438 on_config_ipcsocket_change (xmms_object_t *object, xmmsv_t *_data, gpointer udata)
00439 {
00440     const gchar *value;
00441 
00442     XMMS_DBG ("Shutting down ipc server threads through config property \"core.ipcsocket\" change.");
00443 
00444     xmms_ipc_shutdown ();
00445     value = xmms_config_property_get_string ((xmms_config_property_t *) object);
00446     xmms_ipc_setup_server (value);
00447 }
00448 
00449 /**
00450  * Put a message in the queue awaiting to be sent to the client.
00451  * Should hold client->lock.
00452  */
00453 static gboolean
00454 xmms_ipc_client_msg_write (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg)
00455 {
00456     gboolean queue_empty;
00457 
00458     g_return_val_if_fail (client, FALSE);
00459     g_return_val_if_fail (msg, FALSE);
00460 
00461     queue_empty = g_queue_is_empty (client->out_msg);
00462     g_queue_push_tail (client->out_msg, msg);
00463 
00464     /* If there's no write in progress, add a new callback */
00465     if (queue_empty) {
00466         GMainContext *context = g_main_loop_get_context (client->ml);
00467         GSource *source = g_io_create_watch (client->iochan, G_IO_OUT);
00468 
00469         g_source_set_callback (source,
00470                                (GSourceFunc) xmms_ipc_client_write_cb,
00471                                (gpointer) client,
00472                                NULL);
00473         g_source_attach (source, context);
00474         g_source_unref (source);
00475 
00476         g_main_context_wakeup (context);
00477     }
00478 
00479     return TRUE;
00480 }
00481 
00482 static gboolean
00483 xmms_ipc_source_accept (GIOChannel *chan, GIOCondition cond, gpointer data)
00484 {
00485     xmms_ipc_t *ipc = (xmms_ipc_t *) data;
00486     xmms_ipc_transport_t *transport;
00487     xmms_ipc_client_t *client;
00488 
00489     if (!(cond & G_IO_IN)) {
00490         xmms_log_error ("IPC listener got error/hup");
00491         return FALSE;
00492     }
00493 
00494     XMMS_DBG ("Client connected");
00495     transport = xmms_ipc_server_accept (ipc->transport);
00496     if (!transport) {
00497         xmms_log_error ("accept returned null!");
00498         return TRUE;
00499     }
00500 
00501     client = xmms_ipc_client_new (ipc, transport);
00502     if (!client) {
00503         xmms_ipc_transport_destroy (transport);
00504         return TRUE;
00505     }
00506 
00507     g_mutex_lock (ipc->mutex_lock);
00508     ipc->clients = g_list_append (ipc->clients, client);
00509     g_mutex_unlock (ipc->mutex_lock);
00510 
00511     /* Now that the client has been registered in the ipc->clients list
00512      * we may safely start its thread.
00513      */
00514     g_thread_create (xmms_ipc_client_thread, client, FALSE, NULL);
00515 
00516     return TRUE;
00517 }
00518 
00519 /**
00520  * Enable IPC
00521  */
00522 static gboolean
00523 xmms_ipc_setup_server_internaly (xmms_ipc_t *ipc)
00524 {
00525     g_mutex_lock (ipc->mutex_lock);
00526     ipc->chan = g_io_channel_unix_new (xmms_ipc_transport_fd_get (ipc->transport));
00527 
00528     g_io_channel_set_close_on_unref (ipc->chan, TRUE);
00529     g_io_channel_set_encoding (ipc->chan, NULL, NULL);
00530     g_io_channel_set_buffered (ipc->chan, FALSE);
00531 
00532     g_io_add_watch (ipc->chan, G_IO_IN | G_IO_HUP | G_IO_ERR,
00533                     xmms_ipc_source_accept, ipc);
00534     g_mutex_unlock (ipc->mutex_lock);
00535     return TRUE;
00536 }
00537 
00538 /**
00539  * Checks if someone is waiting for signalid
00540  */
00541 gboolean
00542 xmms_ipc_has_pending (guint signalid)
00543 {
00544     GList *c, *s;
00545     xmms_ipc_t *ipc;
00546 
00547     g_mutex_lock (ipc_servers_lock);
00548 
00549     for (s = ipc_servers; s; s = g_list_next (s)) {
00550         ipc = s->data;
00551         g_mutex_lock (ipc->mutex_lock);
00552         for (c = ipc->clients; c; c = g_list_next (c)) {
00553             xmms_ipc_client_t *cli = c->data;
00554             g_mutex_lock (cli->lock);
00555             if (cli->pendingsignals[signalid]) {
00556                 g_mutex_unlock (cli->lock);
00557                 g_mutex_unlock (ipc->mutex_lock);
00558                 g_mutex_unlock (ipc_servers_lock);
00559                 return TRUE;
00560             }
00561             g_mutex_unlock (cli->lock);
00562         }
00563         g_mutex_unlock (ipc->mutex_lock);
00564     }
00565 
00566     g_mutex_unlock (ipc_servers_lock);
00567     return FALSE;
00568 }
00569 
00570 static void
00571 xmms_ipc_signal_cb (xmms_object_t *object, xmmsv_t *arg, gpointer userdata)
00572 {
00573     GList *c, *s;
00574     guint signalid = GPOINTER_TO_UINT (userdata);
00575     xmms_ipc_t *ipc;
00576     xmms_ipc_msg_t *msg;
00577 
00578     g_mutex_lock (ipc_servers_lock);
00579 
00580     for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
00581         ipc = s->data;
00582         g_mutex_lock (ipc->mutex_lock);
00583         for (c = ipc->clients; c; c = g_list_next (c)) {
00584             xmms_ipc_client_t *cli = c->data;
00585             g_mutex_lock (cli->lock);
00586             if (cli->pendingsignals[signalid]) {
00587                 msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_SIGNAL, XMMS_IPC_CMD_SIGNAL);
00588                 xmms_ipc_msg_set_cookie (msg, cli->pendingsignals[signalid]);
00589                 xmms_ipc_handle_cmd_value (msg, arg);
00590                 xmms_ipc_client_msg_write (cli, msg);
00591                 cli->pendingsignals[signalid] = 0;
00592             }
00593             g_mutex_unlock (cli->lock);
00594         }
00595         g_mutex_unlock (ipc->mutex_lock);
00596     }
00597 
00598     g_mutex_unlock (ipc_servers_lock);
00599 
00600 }
00601 
00602 static void
00603 xmms_ipc_broadcast_cb (xmms_object_t *object, xmmsv_t *arg, gpointer userdata)
00604 {
00605     GList *c, *s;
00606     guint broadcastid = GPOINTER_TO_UINT (userdata);
00607     xmms_ipc_t *ipc;
00608     xmms_ipc_msg_t *msg = NULL;
00609     GList *l;
00610 
00611     g_mutex_lock (ipc_servers_lock);
00612 
00613     for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
00614         ipc = s->data;
00615         g_mutex_lock (ipc->mutex_lock);
00616         for (c = ipc->clients; c; c = g_list_next (c)) {
00617             xmms_ipc_client_t *cli = c->data;
00618 
00619             g_mutex_lock (cli->lock);
00620             for (l = cli->broadcasts[broadcastid]; l; l = g_list_next (l)) {
00621                 msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_SIGNAL, XMMS_IPC_CMD_BROADCAST);
00622                 xmms_ipc_msg_set_cookie (msg, GPOINTER_TO_UINT (l->data));
00623                 xmms_ipc_handle_cmd_value (msg, arg);
00624                 xmms_ipc_client_msg_write (cli, msg);
00625             }
00626             g_mutex_unlock (cli->lock);
00627         }
00628         g_mutex_unlock (ipc->mutex_lock);
00629     }
00630     g_mutex_unlock (ipc_servers_lock);
00631 }
00632 
00633 /**
00634  * Register a broadcast signal.
00635  */
00636 void
00637 xmms_ipc_broadcast_register (xmms_object_t *object, xmms_ipc_signals_t signalid)
00638 {
00639     g_return_if_fail (object);
00640     g_mutex_lock (ipc_object_pool_lock);
00641 
00642     ipc_object_pool->broadcasts[signalid] = object;
00643     xmms_object_connect (object, signalid, xmms_ipc_broadcast_cb, GUINT_TO_POINTER (signalid));
00644 
00645     g_mutex_unlock (ipc_object_pool_lock);
00646 }
00647 
00648 /**
00649  * Unregister a broadcast signal.
00650  */
00651 void
00652 xmms_ipc_broadcast_unregister (xmms_ipc_signals_t signalid)
00653 {
00654     xmms_object_t *obj;
00655 
00656     g_mutex_lock (ipc_object_pool_lock);
00657     obj = ipc_object_pool->broadcasts[signalid];
00658     if (obj) {
00659         xmms_object_disconnect (obj, signalid, xmms_ipc_broadcast_cb, GUINT_TO_POINTER (signalid));
00660         ipc_object_pool->broadcasts[signalid] = NULL;
00661     }
00662     g_mutex_unlock (ipc_object_pool_lock);
00663 }
00664 
00665 /**
00666  * Register a signal
00667  */
00668 void
00669 xmms_ipc_signal_register (xmms_object_t *object, xmms_ipc_signals_t signalid)
00670 {
00671     g_return_if_fail (object);
00672 
00673     g_mutex_lock (ipc_object_pool_lock);
00674     ipc_object_pool->signals[signalid] = object;
00675     xmms_object_connect (object, signalid, xmms_ipc_signal_cb, GUINT_TO_POINTER (signalid));
00676     g_mutex_unlock (ipc_object_pool_lock);
00677 }
00678 
00679 /**
00680  * Unregister a signal
00681  */
00682 void
00683 xmms_ipc_signal_unregister (xmms_ipc_signals_t signalid)
00684 {
00685     xmms_object_t *obj;
00686 
00687     g_mutex_lock (ipc_object_pool_lock);
00688     obj = ipc_object_pool->signals[signalid];
00689     if (obj) {
00690         xmms_object_disconnect (obj, signalid, xmms_ipc_signal_cb, GUINT_TO_POINTER (signalid));
00691         ipc_object_pool->signals[signalid] = NULL;
00692     }
00693     g_mutex_unlock (ipc_object_pool_lock);
00694 }
00695 
00696 /**
00697  * Register a object to the IPC core. This needs to be done if you
00698  * want to send commands to that object from the client.
00699  */
00700 void
00701 xmms_ipc_object_register (xmms_ipc_objects_t objectid, xmms_object_t *object)
00702 {
00703     g_mutex_lock (ipc_object_pool_lock);
00704     ipc_object_pool->objects[objectid] = object;
00705     g_mutex_unlock (ipc_object_pool_lock);
00706 }
00707 
00708 /**
00709  * Remove a object from the IPC core.
00710  */
00711 void
00712 xmms_ipc_object_unregister (xmms_ipc_objects_t objectid)
00713 {
00714     g_mutex_lock (ipc_object_pool_lock);
00715     ipc_object_pool->objects[objectid] = NULL;
00716     g_mutex_unlock (ipc_object_pool_lock);
00717 }
00718 
00719 /**
00720  * Initialize IPC
00721  */
00722 xmms_ipc_t *
00723 xmms_ipc_init (void)
00724 {
00725     ipc_servers_lock = g_mutex_new ();
00726     ipc_object_pool_lock = g_mutex_new ();
00727     ipc_object_pool = g_new0 (xmms_ipc_object_pool_t, 1);
00728     return NULL;
00729 }
00730 
00731 /**
00732  * Shutdown a IPC Server
00733  */
00734 static void
00735 xmms_ipc_shutdown_server (xmms_ipc_t *ipc)
00736 {
00737     GList *c;
00738     xmms_ipc_client_t *co;
00739     if (!ipc) return;
00740 
00741     g_mutex_lock (ipc->mutex_lock);
00742     g_source_remove_by_user_data (ipc);
00743     g_io_channel_unref (ipc->chan);
00744     xmms_ipc_transport_destroy (ipc->transport);
00745 
00746     for (c = ipc->clients; c; c = g_list_next (c)) {
00747         co = c->data;
00748         if (!co) continue;
00749         co->ipc = NULL;
00750     }
00751 
00752     g_list_free (ipc->clients);
00753     g_mutex_unlock (ipc->mutex_lock);
00754     g_mutex_free (ipc->mutex_lock);
00755 
00756     g_free (ipc);
00757 
00758 }
00759 
00760 
00761 /**
00762  * Disable IPC
00763  */
00764 void
00765 xmms_ipc_shutdown (void)
00766 {
00767     GList *s = ipc_servers;
00768     xmms_ipc_t *ipc;
00769 
00770     g_mutex_lock (ipc_servers_lock);
00771     while (s) {
00772         ipc = s->data;
00773         s = g_list_next (s);
00774         ipc_servers = g_list_remove (ipc_servers, ipc);
00775         xmms_ipc_shutdown_server (ipc);
00776     }
00777     g_mutex_unlock (ipc_servers_lock);
00778 
00779 }
00780 
00781 /**
00782  * Start the server
00783  */
00784 gboolean
00785 xmms_ipc_setup_server (const gchar *path)
00786 {
00787     xmms_ipc_transport_t *transport;
00788     xmms_ipc_t *ipc;
00789     gchar **split;
00790     gint i = 0, num_init = 0;
00791     g_return_val_if_fail (path, FALSE);
00792 
00793     split = g_strsplit (path, ";", 0);
00794 
00795     for (i = 0; split && split[i]; i++) {
00796         ipc = g_new0 (xmms_ipc_t, 1);
00797         if (!ipc) {
00798             XMMS_DBG ("No IPC server initialized.");
00799             continue;
00800         }
00801 
00802         transport = xmms_ipc_server_init (split[i]);
00803         if (!transport) {
00804             g_free (ipc);
00805             xmms_log_error ("Couldn't setup IPC listening on '%s'.", split[i]);
00806             continue;
00807         }
00808 
00809 
00810         ipc->mutex_lock = g_mutex_new ();
00811         ipc->transport = transport;
00812         ipc->signals = ipc_object_pool->signals;
00813         ipc->broadcasts = ipc_object_pool->broadcasts;
00814         ipc->objects = ipc_object_pool->objects;
00815 
00816         xmms_ipc_setup_server_internaly (ipc);
00817         xmms_log_info ("IPC listening on '%s'.", split[i]);
00818 
00819         g_mutex_lock (ipc_servers_lock);
00820         ipc_servers = g_list_prepend (ipc_servers, ipc);
00821         g_mutex_unlock (ipc_servers_lock);
00822 
00823         num_init++;
00824     }
00825 
00826     g_strfreev (split);
00827 
00828 
00829     /* If there is less than one socket, there is sth. wrong. */
00830     if (num_init < 1)
00831         return FALSE;
00832 
00833     XMMS_DBG ("IPC setup done.");
00834     return TRUE;
00835 }
00836 
00837 /** @} */
00838