00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <glib.h>
00018
00019 #include "xmms/xmms_log.h"
00020 #include "xmmspriv/xmms_ipc.h"
00021 #include "xmmsc/xmmsc_ipc_msg.h"
00022
00023
00024
00025
00026
00027
00028
00029
00030
00031
00032
00033
00034
00035
00036 typedef struct xmms_ipc_object_pool_t {
00037 xmms_object_t *objects[XMMS_IPC_OBJECT_END];
00038 xmms_object_t *signals[XMMS_IPC_SIGNAL_END];
00039 xmms_object_t *broadcasts[XMMS_IPC_SIGNAL_END];
00040 } xmms_ipc_object_pool_t;
00041
00042
00043
00044
00045
00046 struct xmms_ipc_St {
00047 xmms_ipc_transport_t *transport;
00048 GList *clients;
00049 GIOChannel *chan;
00050 GMutex *mutex_lock;
00051 xmms_object_t **objects;
00052 xmms_object_t **signals;
00053 xmms_object_t **broadcasts;
00054 };
00055
00056
00057
00058
00059
00060 typedef struct xmms_ipc_client_St {
00061 GMainLoop *ml;
00062 GIOChannel *iochan;
00063
00064 xmms_ipc_transport_t *transport;
00065 xmms_ipc_msg_t *read_msg;
00066 xmms_ipc_t *ipc;
00067
00068
00069
00070
00071 GMutex *lock;
00072
00073
00074 GQueue *out_msg;
00075
00076 guint pendingsignals[XMMS_IPC_SIGNAL_END];
00077 GList *broadcasts[XMMS_IPC_SIGNAL_END];
00078 } xmms_ipc_client_t;
00079
00080 static GMutex *ipc_servers_lock;
00081 static GList *ipc_servers = NULL;
00082
00083 static GMutex *ipc_object_pool_lock;
00084 static struct xmms_ipc_object_pool_t *ipc_object_pool = NULL;
00085
00086 static void xmms_ipc_client_destroy (xmms_ipc_client_t *client);
00087
00088 static gboolean xmms_ipc_client_msg_write (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg);
00089 static void xmms_ipc_handle_cmd_value (xmms_ipc_msg_t *msg, xmms_object_cmd_value_t *val);
00090
00091 static gboolean
00092 type_and_msg_to_arg (xmms_object_cmd_arg_type_t type, xmms_ipc_msg_t *msg, xmms_object_cmd_arg_t *arg, gint i)
00093 {
00094 guint len;
00095 guint size, k;
00096
00097 switch (type) {
00098 case XMMS_OBJECT_CMD_ARG_NONE:
00099 break;
00100 case XMMS_OBJECT_CMD_ARG_UINT32 :
00101 if (!xmms_ipc_msg_get_uint32 (msg, &arg->values[i].value.uint32))
00102 return FALSE;
00103 break;
00104 case XMMS_OBJECT_CMD_ARG_INT32 :
00105 if (!xmms_ipc_msg_get_int32 (msg, &arg->values[i].value.int32))
00106 return FALSE;
00107 break;
00108 case XMMS_OBJECT_CMD_ARG_STRING :
00109 if (!xmms_ipc_msg_get_string_alloc (msg, &arg->values[i].value.string, &len)) {
00110 return FALSE;
00111 }
00112 break;
00113 case XMMS_OBJECT_CMD_ARG_STRINGLIST :
00114 if (!xmms_ipc_msg_get_uint32 (msg, &size)) {
00115 return FALSE;
00116 }
00117 for (k = 0; k < size; k++) {
00118 gchar *buf;
00119 if (!xmms_ipc_msg_get_string_alloc (msg, &buf, &len) ||
00120 !(arg->values[i].value.list = g_list_prepend (arg->values[i].value.list, buf))) {
00121 GList * list = arg->values[i].value.list;
00122 while (list) { g_free (list->data); list = g_list_remove (list, list); }
00123 return FALSE;
00124 }
00125 }
00126 arg->values[i].value.list = g_list_reverse (arg->values[i].value.list);
00127 break;
00128 case XMMS_OBJECT_CMD_ARG_COLL :
00129 if (!xmms_ipc_msg_get_collection_alloc (msg, &arg->values[i].value.coll)) {
00130 return FALSE;
00131 }
00132 break;
00133 case XMMS_OBJECT_CMD_ARG_BIN :
00134 {
00135 GString *bin = g_string_new (NULL);
00136 if (!xmms_ipc_msg_get_bin_alloc (msg, (unsigned char **)&bin->str, (uint32_t *)&bin->len)) {
00137 return FALSE;
00138 }
00139 arg->values[i].value.bin = bin;
00140 }
00141 break;
00142 default:
00143 XMMS_DBG ("Unknown value for a caller argument?");
00144 return FALSE;
00145 break;
00146 }
00147 arg->values[i].type = type;
00148 return TRUE;
00149 }
00150
00151 typedef struct dict_to_dict_data_St {
00152 xmms_ipc_msg_t *msg;
00153 guint count;
00154 } dict_to_dict_data_t;
00155
00156 static gboolean
00157 tree_to_dict (gpointer key, gpointer value, gpointer udata)
00158 {
00159 gchar *k = key;
00160 xmms_object_cmd_value_t *v = value;
00161 dict_to_dict_data_t *d = udata;
00162
00163 if (k && v) {
00164 xmms_ipc_msg_put_string (d->msg, k);
00165 xmms_ipc_handle_cmd_value (d->msg, v);
00166 d->count++;
00167 }
00168
00169 return FALSE;
00170 }
00171
00172 static void
00173 xmms_ipc_do_dict (xmms_ipc_msg_t *msg, GTree *dict)
00174 {
00175 dict_to_dict_data_t d = {msg, 0};
00176 guint offset;
00177
00178 offset = xmms_ipc_msg_put_uint32 (msg, 0);
00179 g_tree_foreach (dict, tree_to_dict, &d);
00180 xmms_ipc_msg_store_uint32 (msg, offset, d.count);
00181 }
00182
00183 static void
00184 hash_to_dict (gpointer key, gpointer value, gpointer udata)
00185 {
00186 gchar *k = key;
00187 xmms_object_cmd_value_t *v = value;
00188 dict_to_dict_data_t *d = udata;
00189
00190 if (k && v) {
00191 xmms_ipc_msg_put_string (d->msg, k);
00192 xmms_ipc_handle_cmd_value (d->msg, v);
00193 d->count++;
00194 }
00195 }
00196
00197 static void
00198 xmms_ipc_do_hash (xmms_ipc_msg_t *msg, GHashTable *table)
00199 {
00200 dict_to_dict_data_t d = {msg, 0};
00201 guint offset;
00202
00203 offset = xmms_ipc_msg_put_uint32 (msg, 0);
00204 g_hash_table_foreach (table, hash_to_dict, &d);
00205 xmms_ipc_msg_store_uint32 (msg, offset, d.count);
00206 }
00207
00208 static void
00209 xmms_ipc_handle_cmd_value (xmms_ipc_msg_t *msg, xmms_object_cmd_value_t *val)
00210 {
00211 GList *n;
00212 guint offset, count;
00213
00214
00215
00216
00217 if (val->type == XMMS_OBJECT_CMD_ARG_HASH_TABLE)
00218 xmms_ipc_msg_put_int32 (msg, XMMS_OBJECT_CMD_ARG_DICT);
00219 else
00220 xmms_ipc_msg_put_int32 (msg, val->type);
00221
00222 switch (val->type) {
00223 case XMMS_OBJECT_CMD_ARG_BIN:
00224 xmms_ipc_msg_put_bin (msg, (guchar *)val->value.bin->str, val->value.bin->len);
00225 break;
00226 case XMMS_OBJECT_CMD_ARG_STRING:
00227 xmms_ipc_msg_put_string (msg, val->value.string);
00228 break;
00229 case XMMS_OBJECT_CMD_ARG_UINT32:
00230 xmms_ipc_msg_put_uint32 (msg, val->value.uint32);
00231 break;
00232 case XMMS_OBJECT_CMD_ARG_INT32:
00233 xmms_ipc_msg_put_int32 (msg, val->value.int32);
00234 break;
00235 case XMMS_OBJECT_CMD_ARG_LIST:
00236 case XMMS_OBJECT_CMD_ARG_PROPDICT:
00237
00238
00239
00240 offset = xmms_ipc_msg_put_uint32 (msg, 0);
00241 count = 0;
00242
00243 for (n = val->value.list; n; n = g_list_next (n)) {
00244 xmms_object_cmd_value_t *lval = n->data;
00245
00246 xmms_ipc_handle_cmd_value (msg, lval);
00247 count++;
00248 }
00249
00250
00251
00252
00253 xmms_ipc_msg_store_uint32 (msg, offset, count);
00254
00255 break;
00256 case XMMS_OBJECT_CMD_ARG_DICT:
00257 xmms_ipc_do_dict (msg, val->value.dict);
00258 break;
00259 case XMMS_OBJECT_CMD_ARG_HASH_TABLE:
00260 xmms_ipc_do_hash (msg, val->value.hash);
00261 break;
00262 case XMMS_OBJECT_CMD_ARG_COLL :
00263 xmms_ipc_msg_put_collection (msg, val->value.coll);
00264 break;
00265 case XMMS_OBJECT_CMD_ARG_NONE:
00266 break;
00267 default:
00268 xmms_log_error ("Unknown returnvalue: %d, couldn't serialize message", val->type);
00269 break;
00270 }
00271 }
00272
00273 static void
00274 process_msg (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg)
00275 {
00276 xmms_object_t *object;
00277 xmms_object_cmd_desc_t *cmd;
00278 xmms_object_cmd_arg_t arg;
00279 xmms_ipc_msg_t *retmsg;
00280 uint32_t objid, cmdid;
00281 gint i;
00282
00283 g_return_if_fail (msg);
00284
00285 objid = xmms_ipc_msg_get_object (msg);
00286 cmdid = xmms_ipc_msg_get_cmd (msg);
00287
00288 if (objid == XMMS_IPC_OBJECT_SIGNAL &&
00289 cmdid == XMMS_IPC_CMD_SIGNAL) {
00290 guint signalid;
00291
00292 if (!xmms_ipc_msg_get_uint32 (msg, &signalid)) {
00293 xmms_log_error ("No signalid in this msg?!");
00294 return;
00295 }
00296
00297 if (signalid >= XMMS_IPC_SIGNAL_END) {
00298 xmms_log_error ("Bad signal id (%d)", signalid);
00299 return;
00300 }
00301
00302 g_mutex_lock (client->lock);
00303 client->pendingsignals[signalid] = xmms_ipc_msg_get_cookie (msg);
00304 g_mutex_unlock (client->lock);
00305 return;
00306 } else if (objid == XMMS_IPC_OBJECT_SIGNAL &&
00307 cmdid == XMMS_IPC_CMD_BROADCAST) {
00308 guint broadcastid;
00309
00310 if (!xmms_ipc_msg_get_uint32 (msg, &broadcastid)) {
00311 xmms_log_error ("No broadcastid in this msg?!");
00312 return;
00313 }
00314
00315 if (broadcastid >= XMMS_IPC_SIGNAL_END) {
00316 xmms_log_error ("Bad broadcast id (%d)", broadcastid);
00317 return;
00318 }
00319
00320 g_mutex_lock (client->lock);
00321 client->broadcasts[broadcastid] =
00322 g_list_append (client->broadcasts[broadcastid],
00323 GUINT_TO_POINTER (xmms_ipc_msg_get_cookie (msg)));
00324
00325 g_mutex_unlock (client->lock);
00326 return;
00327 }
00328
00329 if (objid >= XMMS_IPC_OBJECT_END) {
00330 xmms_log_error ("Bad object id (%d)", objid);
00331 return;
00332 }
00333
00334 g_mutex_lock (ipc_object_pool_lock);
00335 object = ipc_object_pool->objects[objid];
00336 g_mutex_unlock (ipc_object_pool_lock);
00337 if (!object) {
00338 xmms_log_error ("Object %d was not found!", objid);
00339 return;
00340 }
00341
00342 if (cmdid >= XMMS_IPC_CMD_END) {
00343 xmms_log_error ("Bad command id (%d)", cmdid);
00344 return;
00345 }
00346
00347 cmd = object->cmds[cmdid];
00348 if (!cmd) {
00349 xmms_log_error ("No such cmd %d on object %d", cmdid, objid);
00350 return;
00351 }
00352
00353 xmms_object_cmd_arg_init (&arg);
00354
00355 for (i = 0; i < XMMS_OBJECT_CMD_MAX_ARGS; i++) {
00356 if (!type_and_msg_to_arg (cmd->args[i], msg, &arg, i)) {
00357 xmms_log_error ("Error parsing args");
00358 retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_ERROR);
00359 xmms_ipc_msg_put_string (retmsg, "Corrupt msg");
00360 goto err;
00361 }
00362
00363 }
00364
00365 xmms_object_cmd_call (object, cmdid, &arg);
00366 if (xmms_error_isok (&arg.error)) {
00367 retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_REPLY);
00368 xmms_ipc_handle_cmd_value (retmsg, arg.retval);
00369 } else {
00370 retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_ERROR);
00371 xmms_ipc_msg_put_string (retmsg, xmms_error_message_get (&arg.error));
00372 }
00373
00374 if (arg.retval)
00375 xmms_object_cmd_value_unref (arg.retval);
00376
00377 err:
00378 for (i = 0; i < XMMS_OBJECT_CMD_MAX_ARGS; i++) {
00379 if (arg.values[i].type == XMMS_OBJECT_CMD_ARG_STRING) {
00380 g_free (arg.values[i].value.string);
00381 } else if (arg.values[i].type == XMMS_OBJECT_CMD_ARG_STRINGLIST) {
00382 GList * list = arg.values[i].value.list;
00383 while (list) { g_free (list->data); list = g_list_delete_link (list, list); }
00384 } else if (arg.values[i].type == XMMS_OBJECT_CMD_ARG_COLL) {
00385 xmmsc_coll_unref (arg.values[i].value.coll);
00386 } else if (arg.values[i].type == XMMS_OBJECT_CMD_ARG_BIN) {
00387 g_string_free (arg.values[i].value.bin, TRUE);
00388 }
00389 }
00390 xmms_ipc_msg_set_cookie (retmsg, xmms_ipc_msg_get_cookie (msg));
00391 g_mutex_lock (client->lock);
00392 xmms_ipc_client_msg_write (client, retmsg);
00393 g_mutex_unlock (client->lock);
00394 }
00395
00396
00397 static gboolean
00398 xmms_ipc_client_read_cb (GIOChannel *iochan,
00399 GIOCondition cond,
00400 gpointer data)
00401 {
00402 xmms_ipc_client_t *client = data;
00403 bool disconnect = FALSE;
00404
00405 g_return_val_if_fail (client, FALSE);
00406
00407 if (cond & G_IO_IN) {
00408 while (TRUE) {
00409 if (!client->read_msg) {
00410 client->read_msg = xmms_ipc_msg_alloc ();
00411 }
00412
00413 if (xmms_ipc_msg_read_transport (client->read_msg, client->transport, &disconnect)) {
00414 xmms_ipc_msg_t *msg = client->read_msg;
00415 client->read_msg = NULL;
00416 process_msg (client, msg);
00417 xmms_ipc_msg_destroy (msg);
00418 } else {
00419 break;
00420 }
00421 }
00422 }
00423
00424 if (disconnect || (cond & G_IO_HUP)) {
00425 if (client->read_msg) {
00426 xmms_ipc_msg_destroy (client->read_msg);
00427 client->read_msg = NULL;
00428 }
00429 XMMS_DBG ("disconnect was true!");
00430 g_main_loop_quit (client->ml);
00431 return FALSE;
00432 }
00433
00434 if (cond & G_IO_ERR) {
00435 xmms_log_error ("Client got error, maybe connection died?");
00436 g_main_loop_quit (client->ml);
00437 return FALSE;
00438 }
00439
00440 return TRUE;
00441 }
00442
00443 static gboolean
00444 xmms_ipc_client_write_cb (GIOChannel *iochan,
00445 GIOCondition cond,
00446 gpointer data)
00447 {
00448 xmms_ipc_client_t *client = data;
00449 bool disconnect = FALSE;
00450
00451 g_return_val_if_fail (client, FALSE);
00452
00453 while (TRUE) {
00454 xmms_ipc_msg_t *msg;
00455
00456 g_mutex_lock (client->lock);
00457 msg = g_queue_peek_head (client->out_msg);
00458 g_mutex_unlock (client->lock);
00459
00460 if (!msg)
00461 break;
00462
00463 if (!xmms_ipc_msg_write_transport (msg,
00464 client->transport,
00465 &disconnect)) {
00466 if (disconnect) {
00467 break;
00468 } else {
00469
00470 return TRUE;
00471 }
00472 }
00473
00474 g_mutex_lock (client->lock);
00475 g_queue_pop_head (client->out_msg);
00476 g_mutex_unlock (client->lock);
00477
00478 xmms_ipc_msg_destroy (msg);
00479 }
00480
00481 return FALSE;
00482 }
00483
00484 static gpointer
00485 xmms_ipc_client_thread (gpointer data)
00486 {
00487 xmms_ipc_client_t *client = data;
00488 GSource *source;
00489
00490 source = g_io_create_watch (client->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP);
00491 g_source_set_callback (source,
00492 (GSourceFunc) xmms_ipc_client_read_cb,
00493 (gpointer) client,
00494 NULL);
00495 g_source_attach (source, g_main_loop_get_context (client->ml));
00496 g_source_unref (source);
00497
00498 g_main_loop_run (client->ml);
00499
00500 xmms_ipc_client_destroy (client);
00501
00502 return NULL;
00503 }
00504
00505 static xmms_ipc_client_t *
00506 xmms_ipc_client_new (xmms_ipc_t *ipc, xmms_ipc_transport_t *transport)
00507 {
00508 xmms_ipc_client_t *client;
00509 GMainContext *context;
00510 int fd;
00511
00512 g_return_val_if_fail (transport, NULL);
00513
00514 client = g_new0 (xmms_ipc_client_t, 1);
00515
00516 context = g_main_context_new ();
00517 client->ml = g_main_loop_new (context, FALSE);
00518 g_main_context_unref (context);
00519
00520 fd = xmms_ipc_transport_fd_get (transport);
00521 client->iochan = g_io_channel_unix_new (fd);
00522 g_return_val_if_fail (client->iochan, NULL);
00523
00524 g_io_channel_set_close_on_unref (client->iochan, TRUE);
00525 g_io_channel_set_encoding (client->iochan, NULL, NULL);
00526 g_io_channel_set_buffered (client->iochan, FALSE);
00527
00528 client->transport = transport;
00529 client->ipc = ipc;
00530 client->out_msg = g_queue_new ();
00531 client->lock = g_mutex_new ();
00532
00533 return client;
00534 }
00535
00536 static void
00537 xmms_ipc_client_destroy (xmms_ipc_client_t *client)
00538 {
00539 guint i;
00540
00541 XMMS_DBG ("Destroying client!");
00542
00543 if (client->ipc) {
00544 g_mutex_lock (client->ipc->mutex_lock);
00545 client->ipc->clients = g_list_remove (client->ipc->clients, client);
00546 g_mutex_unlock (client->ipc->mutex_lock);
00547 }
00548
00549 g_main_loop_unref (client->ml);
00550 g_io_channel_unref (client->iochan);
00551
00552 xmms_ipc_transport_destroy (client->transport);
00553
00554 g_mutex_lock (client->lock);
00555 while (!g_queue_is_empty (client->out_msg)) {
00556 xmms_ipc_msg_t *msg = g_queue_pop_head (client->out_msg);
00557 xmms_ipc_msg_destroy (msg);
00558 }
00559
00560 g_queue_free (client->out_msg);
00561
00562 for (i = 0; i < XMMS_IPC_SIGNAL_END; i++) {
00563 g_list_free (client->broadcasts[i]);
00564 }
00565
00566 g_mutex_unlock (client->lock);
00567 g_mutex_free (client->lock);
00568 g_free (client);
00569 }
00570
00571
00572
00573
00574 void
00575 on_config_ipcsocket_change (xmms_object_t *object, gconstpointer data, gpointer udata)
00576 {
00577 xmms_ipc_shutdown ();
00578 XMMS_DBG ("Shuttind down ipc server threads through config property \"core.ipcsocket\" change.");
00579 xmms_ipc_setup_server ((gchar *)data);
00580 }
00581
00582
00583
00584
00585
00586 static gboolean
00587 xmms_ipc_client_msg_write (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg)
00588 {
00589 gboolean queue_empty;
00590
00591 g_return_val_if_fail (client, FALSE);
00592 g_return_val_if_fail (msg, FALSE);
00593
00594 queue_empty = g_queue_is_empty (client->out_msg);
00595 g_queue_push_tail (client->out_msg, msg);
00596
00597
00598 if (queue_empty) {
00599 GMainContext *context = g_main_loop_get_context (client->ml);
00600 GSource *source = g_io_create_watch (client->iochan, G_IO_OUT);
00601
00602 g_source_set_callback (source,
00603 (GSourceFunc) xmms_ipc_client_write_cb,
00604 (gpointer) client,
00605 NULL);
00606 g_source_attach (source, context);
00607 g_source_unref (source);
00608
00609 g_main_context_wakeup (context);
00610 }
00611
00612 return TRUE;
00613 }
00614
00615 static gboolean
00616 xmms_ipc_source_accept (GIOChannel *chan, GIOCondition cond, gpointer data)
00617 {
00618 xmms_ipc_t *ipc = (xmms_ipc_t *) data;
00619 xmms_ipc_transport_t *transport;
00620 xmms_ipc_client_t *client;
00621
00622 if (!(cond & G_IO_IN)) {
00623 xmms_log_error ("IPC listener got error/hup");
00624 return FALSE;
00625 }
00626
00627 XMMS_DBG ("Client connected");
00628 transport = xmms_ipc_server_accept (ipc->transport);
00629 if (!transport) {
00630 xmms_log_error ("accept returned null!");
00631 return TRUE;
00632 }
00633
00634 client = xmms_ipc_client_new (ipc, transport);
00635 if (!client) {
00636 xmms_ipc_transport_destroy (transport);
00637 return TRUE;
00638 }
00639
00640 g_mutex_lock (ipc->mutex_lock);
00641 ipc->clients = g_list_append (ipc->clients, client);
00642 g_mutex_unlock (ipc->mutex_lock);
00643
00644
00645
00646
00647 g_thread_create (xmms_ipc_client_thread, client, FALSE, NULL);
00648
00649 return TRUE;
00650 }
00651
00652
00653
00654
00655 gboolean
00656 xmms_ipc_setup_server_internaly (xmms_ipc_t *ipc)
00657 {
00658 g_mutex_lock (ipc->mutex_lock);
00659 ipc->chan = g_io_channel_unix_new (xmms_ipc_transport_fd_get (ipc->transport));
00660
00661 g_io_channel_set_close_on_unref (ipc->chan, TRUE);
00662 g_io_channel_set_encoding (ipc->chan, NULL, NULL);
00663 g_io_channel_set_buffered (ipc->chan, FALSE);
00664
00665 g_io_add_watch (ipc->chan, G_IO_IN | G_IO_HUP | G_IO_ERR,
00666 xmms_ipc_source_accept, ipc);
00667 g_mutex_unlock (ipc->mutex_lock);
00668 return TRUE;
00669 }
00670
00671
00672
00673
00674 gboolean
00675 xmms_ipc_has_pending (guint signalid)
00676 {
00677 GList *c, *s;
00678 xmms_ipc_t *ipc;
00679
00680 g_mutex_lock (ipc_servers_lock);
00681
00682 for (s = ipc_servers; s; s = g_list_next (s)) {
00683 ipc = s->data;
00684 g_mutex_lock (ipc->mutex_lock);
00685 for (c = ipc->clients; c; c = g_list_next (c)) {
00686 xmms_ipc_client_t *cli = c->data;
00687 g_mutex_lock (cli->lock);
00688 if (cli->pendingsignals[signalid]) {
00689 g_mutex_unlock (cli->lock);
00690 g_mutex_unlock (ipc->mutex_lock);
00691 g_mutex_unlock (ipc_servers_lock);
00692 return TRUE;
00693 }
00694 g_mutex_unlock (cli->lock);
00695 }
00696 g_mutex_unlock (ipc->mutex_lock);
00697 }
00698
00699 g_mutex_unlock (ipc_servers_lock);
00700 return FALSE;
00701 }
00702
00703 static void
00704 xmms_ipc_signal_cb (xmms_object_t *object, gconstpointer arg, gpointer userdata)
00705 {
00706 GList *c, *s;
00707 guint signalid = GPOINTER_TO_UINT (userdata);
00708 xmms_ipc_t *ipc;
00709 xmms_ipc_msg_t *msg;
00710
00711 g_mutex_lock (ipc_servers_lock);
00712
00713 for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
00714 ipc = s->data;
00715 g_mutex_lock (ipc->mutex_lock);
00716 for (c = ipc->clients; c; c = g_list_next (c)) {
00717 xmms_ipc_client_t *cli = c->data;
00718 g_mutex_lock (cli->lock);
00719 if (cli->pendingsignals[signalid]) {
00720 msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_SIGNAL, XMMS_IPC_CMD_SIGNAL);
00721 xmms_ipc_msg_set_cookie (msg, cli->pendingsignals[signalid]);
00722 xmms_ipc_handle_cmd_value (msg, ((xmms_object_cmd_arg_t*)arg)->retval);
00723 xmms_ipc_client_msg_write (cli, msg);
00724 cli->pendingsignals[signalid] = 0;
00725 }
00726 g_mutex_unlock (cli->lock);
00727 }
00728 g_mutex_unlock (ipc->mutex_lock);
00729 }
00730
00731 g_mutex_unlock (ipc_servers_lock);
00732
00733 }
00734
00735 static void
00736 xmms_ipc_broadcast_cb (xmms_object_t *object, gconstpointer arg, gpointer userdata)
00737 {
00738 GList *c, *s;
00739 guint broadcastid = GPOINTER_TO_UINT (userdata);
00740 xmms_ipc_t *ipc;
00741 xmms_ipc_msg_t *msg = NULL;
00742 GList *l;
00743
00744 g_mutex_lock (ipc_servers_lock);
00745
00746 for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
00747 ipc = s->data;
00748 g_mutex_lock (ipc->mutex_lock);
00749 for (c = ipc->clients; c; c = g_list_next (c)) {
00750 xmms_ipc_client_t *cli = c->data;
00751
00752 g_mutex_lock (cli->lock);
00753 for (l = cli->broadcasts[broadcastid]; l; l = g_list_next (l)) {
00754 msg = xmms_ipc_msg_new (XMMS_IPC_OBJECT_SIGNAL, XMMS_IPC_CMD_BROADCAST);
00755 xmms_ipc_msg_set_cookie (msg, GPOINTER_TO_UINT (l->data));
00756 xmms_ipc_handle_cmd_value (msg, ((xmms_object_cmd_arg_t*)arg)->retval);
00757 xmms_ipc_client_msg_write (cli, msg);
00758 }
00759 g_mutex_unlock (cli->lock);
00760 }
00761 g_mutex_unlock (ipc->mutex_lock);
00762 }
00763 g_mutex_unlock (ipc_servers_lock);
00764 }
00765
00766
00767
00768
00769 void
00770 xmms_ipc_broadcast_register (xmms_object_t *object, xmms_ipc_signals_t signalid)
00771 {
00772 g_return_if_fail (object);
00773 g_mutex_lock (ipc_object_pool_lock);
00774
00775 ipc_object_pool->broadcasts[signalid] = object;
00776 xmms_object_connect (object, signalid, xmms_ipc_broadcast_cb, GUINT_TO_POINTER (signalid));
00777
00778 g_mutex_unlock (ipc_object_pool_lock);
00779 }
00780
00781
00782
00783
00784 void
00785 xmms_ipc_broadcast_unregister (xmms_ipc_signals_t signalid)
00786 {
00787 xmms_object_t *obj;
00788
00789 g_mutex_lock (ipc_object_pool_lock);
00790 obj = ipc_object_pool->broadcasts[signalid];
00791 if (obj) {
00792 xmms_object_disconnect (obj, signalid, xmms_ipc_broadcast_cb, GUINT_TO_POINTER (signalid));
00793 ipc_object_pool->broadcasts[signalid] = NULL;
00794 }
00795 g_mutex_unlock (ipc_object_pool_lock);
00796 }
00797
00798
00799
00800
00801 void
00802 xmms_ipc_signal_register (xmms_object_t *object, xmms_ipc_signals_t signalid)
00803 {
00804 g_return_if_fail (object);
00805
00806 g_mutex_lock (ipc_object_pool_lock);
00807 ipc_object_pool->signals[signalid] = object;
00808 xmms_object_connect (object, signalid, xmms_ipc_signal_cb, GUINT_TO_POINTER (signalid));
00809 g_mutex_unlock (ipc_object_pool_lock);
00810 }
00811
00812
00813
00814
00815 void
00816 xmms_ipc_signal_unregister (xmms_ipc_signals_t signalid)
00817 {
00818 xmms_object_t *obj;
00819
00820 g_mutex_lock (ipc_object_pool_lock);
00821 obj = ipc_object_pool->signals[signalid];
00822 if (obj) {
00823 xmms_object_disconnect (obj, signalid, xmms_ipc_signal_cb, GUINT_TO_POINTER (signalid));
00824 ipc_object_pool->signals[signalid] = NULL;
00825 }
00826 g_mutex_unlock (ipc_object_pool_lock);
00827 }
00828
00829
00830
00831
00832
00833 void
00834 xmms_ipc_object_register (xmms_ipc_objects_t objectid, xmms_object_t *object)
00835 {
00836 g_mutex_lock (ipc_object_pool_lock);
00837 ipc_object_pool->objects[objectid] = object;
00838 g_mutex_unlock (ipc_object_pool_lock);
00839 }
00840
00841
00842
00843
00844 void
00845 xmms_ipc_object_unregister (xmms_ipc_objects_t objectid)
00846 {
00847 g_mutex_lock (ipc_object_pool_lock);
00848 ipc_object_pool->objects[objectid] = NULL;
00849 g_mutex_unlock (ipc_object_pool_lock);
00850 }
00851
00852
00853
00854
00855 xmms_ipc_t *
00856 xmms_ipc_init (void)
00857 {
00858 ipc_servers_lock = g_mutex_new ();
00859 ipc_object_pool_lock = g_mutex_new ();
00860 ipc_object_pool = g_new0 (xmms_ipc_object_pool_t, 1);
00861 return NULL;
00862 }
00863
00864
00865
00866
00867 void
00868 xmms_ipc_shutdown_server (xmms_ipc_t *ipc)
00869 {
00870 GList *c;
00871 xmms_ipc_client_t *co;
00872 if (!ipc) return;
00873
00874 g_mutex_lock (ipc->mutex_lock);
00875 g_source_remove_by_user_data (ipc);
00876 g_io_channel_unref (ipc->chan);
00877 xmms_ipc_transport_destroy (ipc->transport);
00878
00879 for (c = ipc->clients; c; c = g_list_next (c)) {
00880 co = c->data;
00881 if (!co) continue;
00882 co->ipc = NULL;
00883 }
00884
00885 g_list_free (ipc->clients);
00886 g_mutex_unlock (ipc->mutex_lock);
00887 g_mutex_free (ipc->mutex_lock);
00888
00889 g_free (ipc);
00890
00891 }
00892
00893
00894
00895
00896
00897 void
00898 xmms_ipc_shutdown (void)
00899 {
00900 GList *s = ipc_servers;
00901 xmms_ipc_t *ipc;
00902
00903 g_mutex_lock (ipc_servers_lock);
00904 while (s) {
00905 ipc = s->data;
00906 s = g_list_next (s);
00907 ipc_servers = g_list_remove (ipc_servers, ipc);
00908 xmms_ipc_shutdown_server (ipc);
00909 }
00910 g_mutex_unlock (ipc_servers_lock);
00911
00912 }
00913
00914
00915
00916
00917 gboolean
00918 xmms_ipc_setup_server (const gchar *path)
00919 {
00920 xmms_ipc_transport_t *transport;
00921 xmms_ipc_t *ipc;
00922 gchar **split;
00923 gint i = 0, num_init = 0;
00924 g_return_val_if_fail (path, FALSE);
00925
00926 split = g_strsplit (path, ";", 0);
00927
00928 for (i = 0; split && split[i]; i++) {
00929 ipc = g_new0 (xmms_ipc_t, 1);
00930 if (!ipc) {
00931 XMMS_DBG ("No IPC server initialized.");
00932 continue;
00933 }
00934
00935 transport = xmms_ipc_server_init (split[i]);
00936 if (!transport) {
00937 g_free (ipc);
00938 xmms_log_error ("Couldn't setup IPC listening on '%s'.", split[i]);
00939 continue;
00940 }
00941
00942
00943 ipc->mutex_lock = g_mutex_new ();
00944 ipc->transport = transport;
00945 ipc->signals = ipc_object_pool->signals;
00946 ipc->broadcasts = ipc_object_pool->broadcasts;
00947 ipc->objects = ipc_object_pool->objects;
00948
00949 xmms_ipc_setup_server_internaly (ipc);
00950 xmms_log_info ("IPC listening on '%s'.", split[i]);
00951
00952 g_mutex_lock (ipc_servers_lock);
00953 ipc_servers = g_list_prepend (ipc_servers, ipc);
00954 g_mutex_unlock (ipc_servers_lock);
00955
00956 num_init++;
00957 }
00958
00959 g_strfreev (split);
00960
00961
00962
00963 if (num_init < 1)
00964 return FALSE;
00965
00966 XMMS_DBG ("IPC setup done.");
00967 return TRUE;
00968 }
00969
00970
00971