• Main Page
  • Related Pages
  • Modules
  • Data Structures
  • Files
  • File List
  • Globals

src/xmms/ipc.c

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

Generated on Wed Feb 9 2011 for XMMS2 by  doxygen 1.7.1