XMMS2
|
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