XMMS2
ipc.c
Go to the documentation of this file.
1/* XMMS2 - X Music Multiplexer System
2 * Copyright (C) 2003-2011 XMMS2 Team
3 *
4 * PLUGINS ARE NOT CONSIDERED TO BE DERIVED WORK !!!
5 *
6 * This library is free software; you can redistribute it and/or
7 * modify it under the terms of the GNU Lesser General Public
8 * License as published by the Free Software Foundation; either
9 * version 2.1 of the License, or (at your option) any later version.
10 *
11 * This library is distributed in the hope that it will be useful,
12 * but WITHOUT ANY WARRANTY; without even the implied warranty of
13 * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
14 * Lesser General Public License for more details.
15 */
16
17#include <glib.h>
18#include <string.h>
19
20#include "xmms/xmms_log.h"
21#include "xmms/xmms_config.h"
23#include "xmmspriv/xmms_ipc.h"
24#include "xmmsc/xmmsc_ipc_msg.h"
25
26
27/**
28 * @defgroup IPC IPC
29 * @ingroup XMMSServer
30 * @brief IPC functions for XMMS2 Daemon
31 * @{
32 */
33
34
35
36/**
37 * The IPC object list
38 */
39typedef struct xmms_ipc_object_pool_t {
44
45
46/**
47 * The server IPC object
48 */
49struct xmms_ipc_St {
50 xmms_ipc_transport_t *transport;
51 GList *clients;
52 GIOChannel *chan;
53 GMutex *mutex_lock;
54 xmms_object_t **objects;
55 xmms_object_t **signals;
56 xmms_object_t **broadcasts;
57};
58
59
60/**
61 * A IPC client representation.
62 */
63typedef struct xmms_ipc_client_St {
64 GMainLoop *ml;
65 GIOChannel *iochan;
66
67 xmms_ipc_transport_t *transport;
68 xmms_ipc_msg_t *read_msg;
69 xmms_ipc_t *ipc;
70
71 /* this lock protects out_msg, pendingsignals and broadcasts,
72 which can be accessed from other threads than the
73 client-thread */
74 GMutex *lock;
75
76 /** Messages waiting to be written */
77 GQueue *out_msg;
78
79 guint pendingsignals[XMMS_IPC_SIGNAL_END];
80 GList *broadcasts[XMMS_IPC_SIGNAL_END];
82
83static GMutex *ipc_servers_lock;
84static GList *ipc_servers = NULL;
85
86static GMutex *ipc_object_pool_lock;
87static struct xmms_ipc_object_pool_t *ipc_object_pool = NULL;
88
89static void xmms_ipc_client_destroy (xmms_ipc_client_t *client);
90
91static void xmms_ipc_register_signal (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg, xmmsv_t *arguments);
92static void xmms_ipc_register_broadcast (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg, xmmsv_t *arguments);
93static gboolean xmms_ipc_client_msg_write (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg);
94
95static void
96xmms_ipc_handle_cmd_value (xmms_ipc_msg_t *msg, xmmsv_t *val)
97{
98 if (xmms_ipc_msg_put_value (msg, val) == (uint32_t) -1) {
99 xmms_log_error ("Failed to serialize the return value into the IPC message!");
100 }
101}
102
103static void
104xmms_ipc_register_signal (xmms_ipc_client_t *client,
105 xmms_ipc_msg_t *msg, xmmsv_t *arguments)
106{
107 xmmsv_t *arg;
108 gint32 signalid;
109 int r;
110
111 if (!arguments || !xmmsv_list_get (arguments, 0, &arg)) {
112 xmms_log_error ("No signalid in this msg?!");
113 return;
114 }
115
116 r = xmmsv_get_int (arg, &signalid);
117
118 if (!r) {
119 xmms_log_error ("Cannot extract signal id from value");
120 return;
121 }
122
123 if (signalid < 0 || signalid >= XMMS_IPC_SIGNAL_END) {
124 xmms_log_error ("Bad signal id (%d)", signalid);
125 return;
126 }
127
128 g_mutex_lock (client->lock);
129 client->pendingsignals[signalid] = xmms_ipc_msg_get_cookie (msg);
130 g_mutex_unlock (client->lock);
131}
132
133static void
134xmms_ipc_register_broadcast (xmms_ipc_client_t *client,
135 xmms_ipc_msg_t *msg, xmmsv_t *arguments)
136{
137 xmmsv_t *arg;
138 gint32 broadcastid;
139 int r;
140
141 if (!arguments || !xmmsv_list_get (arguments, 0, &arg)) {
142 xmms_log_error ("No broadcastid in this msg?!");
143 return;
144 }
145
146 r = xmmsv_get_int (arg, &broadcastid);
147
148 if (!r) {
149 xmms_log_error ("Cannot extract broadcast id from value");
150 return;
151 }
152
153 if (broadcastid < 0 || broadcastid >= XMMS_IPC_SIGNAL_END) {
154 xmms_log_error ("Bad broadcast id (%d)", broadcastid);
155 return;
156 }
157
158 g_mutex_lock (client->lock);
159 client->broadcasts[broadcastid] =
160 g_list_append (client->broadcasts[broadcastid],
161 GUINT_TO_POINTER (xmms_ipc_msg_get_cookie (msg)));
162
163 g_mutex_unlock (client->lock);
164}
165
166static void
167process_msg (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg)
168{
169 xmms_object_t *object;
171 xmms_ipc_msg_t *retmsg;
172 xmmsv_t *error, *arguments;
173 uint32_t objid, cmdid;
174
175 g_return_if_fail (msg);
176
177 objid = xmms_ipc_msg_get_object (msg);
178 cmdid = xmms_ipc_msg_get_cmd (msg);
179
180 if (!xmms_ipc_msg_get_value (msg, &arguments)) {
181 xmms_log_error ("Cannot read command arguments. "
182 "Ignoring command.");
183
184 return;
185 }
186
187 if (objid == XMMS_IPC_OBJECT_SIGNAL) {
188 if (cmdid == XMMS_IPC_CMD_SIGNAL) {
189 xmms_ipc_register_signal (client, msg, arguments);
190 } else if (cmdid == XMMS_IPC_CMD_BROADCAST) {
191 xmms_ipc_register_broadcast (client, msg, arguments);
192 } else {
193 xmms_log_error ("Bad command id (%d) for signal object", cmdid);
194 }
195
196 goto out;
197 }
198
199 if (objid >= XMMS_IPC_OBJECT_END) {
200 xmms_log_error ("Bad object id (%d)", objid);
201 goto out;
202 }
203
204 g_mutex_lock (ipc_object_pool_lock);
205 object = ipc_object_pool->objects[objid];
206 g_mutex_unlock (ipc_object_pool_lock);
207 if (!object) {
208 xmms_log_error ("Object %d was not found!", objid);
209 goto out;
210 }
211
212 if (!g_tree_lookup (object->cmds, GUINT_TO_POINTER (cmdid))) {
213 xmms_log_error ("No such cmd %d on object %d", cmdid, objid);
214 goto out;
215 }
216
218 arg.args = arguments;
219
220 xmms_object_cmd_call (object, cmdid, &arg);
221 if (xmms_error_isok (&arg.error)) {
222 retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_REPLY);
223 xmms_ipc_handle_cmd_value (retmsg, arg.retval);
224 } else {
225 /* FIXME: or we could omit setting the command to _CMD_ERROR
226 * and let the client check whether the value it got is an
227 * error xmmsv_t. If so, don't forget to
228 * update the client-side of IPC too. */
229 retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_ERROR);
230
232 xmms_ipc_msg_put_value (retmsg, error);
233 xmmsv_unref (error);
234
235/*
236 retmsg = xmms_ipc_msg_new (objid, XMMS_IPC_CMD_REPLY);
237 xmms_ipc_handle_cmd_value (retmsg, arg.retval);
238*/
239 }
240
241 if (arg.retval)
242 xmmsv_unref (arg.retval);
243
245 g_mutex_lock (client->lock);
246 xmms_ipc_client_msg_write (client, retmsg);
247 g_mutex_unlock (client->lock);
248
249out:
250 if (arguments) {
251 xmmsv_unref (arguments);
252 }
253}
254
255
256static gboolean
257xmms_ipc_client_read_cb (GIOChannel *iochan,
258 GIOCondition cond,
259 gpointer data)
260{
261 xmms_ipc_client_t *client = data;
262 bool disconnect = FALSE;
263
264 g_return_val_if_fail (client, FALSE);
265
266 if (cond & G_IO_IN) {
267 while (TRUE) {
268 if (!client->read_msg) {
269 client->read_msg = xmms_ipc_msg_alloc ();
270 }
271
272 if (xmms_ipc_msg_read_transport (client->read_msg, client->transport, &disconnect)) {
273 xmms_ipc_msg_t *msg = client->read_msg;
274 client->read_msg = NULL;
275 process_msg (client, msg);
277 } else {
278 break;
279 }
280 }
281 }
282
283 if (disconnect || (cond & G_IO_HUP)) {
284 if (client->read_msg) {
285 xmms_ipc_msg_destroy (client->read_msg);
286 client->read_msg = NULL;
287 }
288 XMMS_DBG ("disconnect was true!");
289 g_main_loop_quit (client->ml);
290 return FALSE;
291 }
292
293 if (cond & G_IO_ERR) {
294 xmms_log_error ("Client got error, maybe connection died?");
295 g_main_loop_quit (client->ml);
296 return FALSE;
297 }
298
299 return TRUE;
300}
301
302static gboolean
303xmms_ipc_client_write_cb (GIOChannel *iochan,
304 GIOCondition cond,
305 gpointer data)
306{
307 xmms_ipc_client_t *client = data;
308 bool disconnect = FALSE;
309
310 g_return_val_if_fail (client, FALSE);
311
312 while (TRUE) {
313 xmms_ipc_msg_t *msg;
314
315 g_mutex_lock (client->lock);
316 msg = g_queue_peek_head (client->out_msg);
317 g_mutex_unlock (client->lock);
318
319 if (!msg)
320 break;
321
323 client->transport,
324 &disconnect)) {
325 if (disconnect) {
326 break;
327 } else {
328 /* try sending again later */
329 return TRUE;
330 }
331 }
332
333 g_mutex_lock (client->lock);
334 g_queue_pop_head (client->out_msg);
335 g_mutex_unlock (client->lock);
336
338 }
339
340 return FALSE;
341}
342
343static gpointer
344xmms_ipc_client_thread (gpointer data)
345{
346 xmms_ipc_client_t *client = data;
347 GSource *source;
348
349 xmms_set_thread_name ("x2 client");
350
351 source = g_io_create_watch (client->iochan, G_IO_IN | G_IO_ERR | G_IO_HUP);
352 g_source_set_callback (source,
353 (GSourceFunc) xmms_ipc_client_read_cb,
354 (gpointer) client,
355 NULL);
356 g_source_attach (source, g_main_loop_get_context (client->ml));
357 g_source_unref (source);
358
359 g_main_loop_run (client->ml);
360
361 xmms_ipc_client_destroy (client);
362
363 return NULL;
364}
365
366static xmms_ipc_client_t *
367xmms_ipc_client_new (xmms_ipc_t *ipc, xmms_ipc_transport_t *transport)
368{
369 xmms_ipc_client_t *client;
370 GMainContext *context;
371 int fd;
372
373 g_return_val_if_fail (transport, NULL);
374
375 client = g_new0 (xmms_ipc_client_t, 1);
376
377 context = g_main_context_new ();
378 client->ml = g_main_loop_new (context, FALSE);
379 g_main_context_unref (context);
380
381 fd = xmms_ipc_transport_fd_get (transport);
382 client->iochan = g_io_channel_unix_new (fd);
383 g_return_val_if_fail (client->iochan, NULL);
384
385 /* We don't set the close_on_unref flag here, because
386 * the transport will close the fd for us. No need to close it twice.
387 */
388 g_io_channel_set_encoding (client->iochan, NULL, NULL);
389 g_io_channel_set_buffered (client->iochan, FALSE);
390
391 client->transport = transport;
392 client->ipc = ipc;
393 client->out_msg = g_queue_new ();
394 client->lock = g_mutex_new ();
395
396 return client;
397}
398
399static void
400xmms_ipc_client_destroy (xmms_ipc_client_t *client)
401{
402 guint i;
403
404 XMMS_DBG ("Destroying client!");
405
406 if (client->ipc) {
407 g_mutex_lock (client->ipc->mutex_lock);
408 client->ipc->clients = g_list_remove (client->ipc->clients, client);
409 g_mutex_unlock (client->ipc->mutex_lock);
410 }
411
412 g_main_loop_unref (client->ml);
413 g_io_channel_unref (client->iochan);
414
415 xmms_ipc_transport_destroy (client->transport);
416
417 g_mutex_lock (client->lock);
418 while (!g_queue_is_empty (client->out_msg)) {
419 xmms_ipc_msg_t *msg = g_queue_pop_head (client->out_msg);
421 }
422
423 g_queue_free (client->out_msg);
424
425 for (i = 0; i < XMMS_IPC_SIGNAL_END; i++) {
426 g_list_free (client->broadcasts[i]);
427 }
428
429 g_mutex_unlock (client->lock);
430 g_mutex_free (client->lock);
431 g_free (client);
432}
433
434/**
435 * Gets called when the config property "core.ipcsocket" has changed.
436 */
437void
438on_config_ipcsocket_change (xmms_object_t *object, xmmsv_t *_data, gpointer udata)
439{
440 const gchar *value;
441
442 XMMS_DBG ("Shutting down ipc server threads through config property \"core.ipcsocket\" change.");
443
446 xmms_ipc_setup_server (value);
447}
448
449/**
450 * Put a message in the queue awaiting to be sent to the client.
451 * Should hold client->lock.
452 */
453static gboolean
454xmms_ipc_client_msg_write (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg)
455{
456 gboolean queue_empty;
457
458 g_return_val_if_fail (client, FALSE);
459 g_return_val_if_fail (msg, FALSE);
460
461 queue_empty = g_queue_is_empty (client->out_msg);
462 g_queue_push_tail (client->out_msg, msg);
463
464 /* If there's no write in progress, add a new callback */
465 if (queue_empty) {
466 GMainContext *context = g_main_loop_get_context (client->ml);
467 GSource *source = g_io_create_watch (client->iochan, G_IO_OUT);
468
469 g_source_set_callback (source,
470 (GSourceFunc) xmms_ipc_client_write_cb,
471 (gpointer) client,
472 NULL);
473 g_source_attach (source, context);
474 g_source_unref (source);
475
476 g_main_context_wakeup (context);
477 }
478
479 return TRUE;
480}
481
482static gboolean
483xmms_ipc_source_accept (GIOChannel *chan, GIOCondition cond, gpointer data)
484{
485 xmms_ipc_t *ipc = (xmms_ipc_t *) data;
486 xmms_ipc_transport_t *transport;
487 xmms_ipc_client_t *client;
488
489 if (!(cond & G_IO_IN)) {
490 xmms_log_error ("IPC listener got error/hup");
491 return FALSE;
492 }
493
494 XMMS_DBG ("Client connected");
495 transport = xmms_ipc_server_accept (ipc->transport);
496 if (!transport) {
497 xmms_log_error ("accept returned null!");
498 return TRUE;
499 }
500
501 client = xmms_ipc_client_new (ipc, transport);
502 if (!client) {
503 xmms_ipc_transport_destroy (transport);
504 return TRUE;
505 }
506
507 g_mutex_lock (ipc->mutex_lock);
508 ipc->clients = g_list_append (ipc->clients, client);
509 g_mutex_unlock (ipc->mutex_lock);
510
511 /* Now that the client has been registered in the ipc->clients list
512 * we may safely start its thread.
513 */
514 g_thread_create (xmms_ipc_client_thread, client, FALSE, NULL);
515
516 return TRUE;
517}
518
519/**
520 * Enable IPC
521 */
522static gboolean
523xmms_ipc_setup_server_internaly (xmms_ipc_t *ipc)
524{
525 g_mutex_lock (ipc->mutex_lock);
526 ipc->chan = g_io_channel_unix_new (xmms_ipc_transport_fd_get (ipc->transport));
527
528 g_io_channel_set_close_on_unref (ipc->chan, TRUE);
529 g_io_channel_set_encoding (ipc->chan, NULL, NULL);
530 g_io_channel_set_buffered (ipc->chan, FALSE);
531
532 g_io_add_watch (ipc->chan, G_IO_IN | G_IO_HUP | G_IO_ERR,
533 xmms_ipc_source_accept, ipc);
534 g_mutex_unlock (ipc->mutex_lock);
535 return TRUE;
536}
537
538/**
539 * Checks if someone is waiting for signalid
540 */
541gboolean
542xmms_ipc_has_pending (guint signalid)
543{
544 GList *c, *s;
545 xmms_ipc_t *ipc;
546
547 g_mutex_lock (ipc_servers_lock);
548
549 for (s = ipc_servers; s; s = g_list_next (s)) {
550 ipc = s->data;
551 g_mutex_lock (ipc->mutex_lock);
552 for (c = ipc->clients; c; c = g_list_next (c)) {
553 xmms_ipc_client_t *cli = c->data;
554 g_mutex_lock (cli->lock);
555 if (cli->pendingsignals[signalid]) {
556 g_mutex_unlock (cli->lock);
557 g_mutex_unlock (ipc->mutex_lock);
558 g_mutex_unlock (ipc_servers_lock);
559 return TRUE;
560 }
561 g_mutex_unlock (cli->lock);
562 }
563 g_mutex_unlock (ipc->mutex_lock);
564 }
565
566 g_mutex_unlock (ipc_servers_lock);
567 return FALSE;
568}
569
570static void
571xmms_ipc_signal_cb (xmms_object_t *object, xmmsv_t *arg, gpointer userdata)
572{
573 GList *c, *s;
574 guint signalid = GPOINTER_TO_UINT (userdata);
575 xmms_ipc_t *ipc;
576 xmms_ipc_msg_t *msg;
577
578 g_mutex_lock (ipc_servers_lock);
579
580 for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
581 ipc = s->data;
582 g_mutex_lock (ipc->mutex_lock);
583 for (c = ipc->clients; c; c = g_list_next (c)) {
584 xmms_ipc_client_t *cli = c->data;
585 g_mutex_lock (cli->lock);
586 if (cli->pendingsignals[signalid]) {
588 xmms_ipc_msg_set_cookie (msg, cli->pendingsignals[signalid]);
589 xmms_ipc_handle_cmd_value (msg, arg);
590 xmms_ipc_client_msg_write (cli, msg);
591 cli->pendingsignals[signalid] = 0;
592 }
593 g_mutex_unlock (cli->lock);
594 }
595 g_mutex_unlock (ipc->mutex_lock);
596 }
597
598 g_mutex_unlock (ipc_servers_lock);
599
600}
601
602static void
603xmms_ipc_broadcast_cb (xmms_object_t *object, xmmsv_t *arg, gpointer userdata)
604{
605 GList *c, *s;
606 guint broadcastid = GPOINTER_TO_UINT (userdata);
607 xmms_ipc_t *ipc;
608 xmms_ipc_msg_t *msg = NULL;
609 GList *l;
610
611 g_mutex_lock (ipc_servers_lock);
612
613 for (s = ipc_servers; s && s->data; s = g_list_next (s)) {
614 ipc = s->data;
615 g_mutex_lock (ipc->mutex_lock);
616 for (c = ipc->clients; c; c = g_list_next (c)) {
617 xmms_ipc_client_t *cli = c->data;
618
619 g_mutex_lock (cli->lock);
620 for (l = cli->broadcasts[broadcastid]; l; l = g_list_next (l)) {
622 xmms_ipc_msg_set_cookie (msg, GPOINTER_TO_UINT (l->data));
623 xmms_ipc_handle_cmd_value (msg, arg);
624 xmms_ipc_client_msg_write (cli, msg);
625 }
626 g_mutex_unlock (cli->lock);
627 }
628 g_mutex_unlock (ipc->mutex_lock);
629 }
630 g_mutex_unlock (ipc_servers_lock);
631}
632
633/**
634 * Register a broadcast signal.
635 */
636void
638{
639 g_return_if_fail (object);
640 g_mutex_lock (ipc_object_pool_lock);
641
642 ipc_object_pool->broadcasts[signalid] = object;
643 xmms_object_connect (object, signalid, xmms_ipc_broadcast_cb, GUINT_TO_POINTER (signalid));
644
645 g_mutex_unlock (ipc_object_pool_lock);
646}
647
648/**
649 * Unregister a broadcast signal.
650 */
651void
653{
654 xmms_object_t *obj;
655
656 g_mutex_lock (ipc_object_pool_lock);
657 obj = ipc_object_pool->broadcasts[signalid];
658 if (obj) {
659 xmms_object_disconnect (obj, signalid, xmms_ipc_broadcast_cb, GUINT_TO_POINTER (signalid));
660 ipc_object_pool->broadcasts[signalid] = NULL;
661 }
662 g_mutex_unlock (ipc_object_pool_lock);
663}
664
665/**
666 * Register a signal
667 */
668void
670{
671 g_return_if_fail (object);
672
673 g_mutex_lock (ipc_object_pool_lock);
674 ipc_object_pool->signals[signalid] = object;
675 xmms_object_connect (object, signalid, xmms_ipc_signal_cb, GUINT_TO_POINTER (signalid));
676 g_mutex_unlock (ipc_object_pool_lock);
677}
678
679/**
680 * Unregister a signal
681 */
682void
684{
685 xmms_object_t *obj;
686
687 g_mutex_lock (ipc_object_pool_lock);
688 obj = ipc_object_pool->signals[signalid];
689 if (obj) {
690 xmms_object_disconnect (obj, signalid, xmms_ipc_signal_cb, GUINT_TO_POINTER (signalid));
691 ipc_object_pool->signals[signalid] = NULL;
692 }
693 g_mutex_unlock (ipc_object_pool_lock);
694}
695
696/**
697 * Register a object to the IPC core. This needs to be done if you
698 * want to send commands to that object from the client.
699 */
700void
702{
703 g_mutex_lock (ipc_object_pool_lock);
704 ipc_object_pool->objects[objectid] = object;
705 g_mutex_unlock (ipc_object_pool_lock);
706}
707
708/**
709 * Remove a object from the IPC core.
710 */
711void
713{
714 g_mutex_lock (ipc_object_pool_lock);
715 ipc_object_pool->objects[objectid] = NULL;
716 g_mutex_unlock (ipc_object_pool_lock);
717}
718
719/**
720 * Initialize IPC
721 */
724{
725 ipc_servers_lock = g_mutex_new ();
726 ipc_object_pool_lock = g_mutex_new ();
727 ipc_object_pool = g_new0 (xmms_ipc_object_pool_t, 1);
728 return NULL;
729}
730
731/**
732 * Shutdown a IPC Server
733 */
734static void
735xmms_ipc_shutdown_server (xmms_ipc_t *ipc)
736{
737 GList *c;
739 if (!ipc) return;
740
741 g_mutex_lock (ipc->mutex_lock);
742 g_source_remove_by_user_data (ipc);
743 g_io_channel_unref (ipc->chan);
744 xmms_ipc_transport_destroy (ipc->transport);
745
746 for (c = ipc->clients; c; c = g_list_next (c)) {
747 co = c->data;
748 if (!co) continue;
749 co->ipc = NULL;
750 }
751
752 g_list_free (ipc->clients);
753 g_mutex_unlock (ipc->mutex_lock);
754 g_mutex_free (ipc->mutex_lock);
755
756 g_free (ipc);
757
758}
759
760
761/**
762 * Disable IPC
763 */
764void
766{
767 GList *s = ipc_servers;
768 xmms_ipc_t *ipc;
769
770 g_mutex_lock (ipc_servers_lock);
771 while (s) {
772 ipc = s->data;
773 s = g_list_next (s);
774 ipc_servers = g_list_remove (ipc_servers, ipc);
775 xmms_ipc_shutdown_server (ipc);
776 }
777 g_mutex_unlock (ipc_servers_lock);
778
779}
780
781/**
782 * Start the server
783 */
784gboolean
785xmms_ipc_setup_server (const gchar *path)
786{
787 xmms_ipc_transport_t *transport;
788 xmms_ipc_t *ipc;
789 gchar **split;
790 gint i = 0, num_init = 0;
791 g_return_val_if_fail (path, FALSE);
792
793 split = g_strsplit (path, ";", 0);
794
795 for (i = 0; split && split[i]; i++) {
796 ipc = g_new0 (xmms_ipc_t, 1);
797 if (!ipc) {
798 XMMS_DBG ("No IPC server initialized.");
799 continue;
800 }
801
802 transport = xmms_ipc_server_init (split[i]);
803 if (!transport) {
804 g_free (ipc);
805 xmms_log_error ("Couldn't setup IPC listening on '%s'.", split[i]);
806 continue;
807 }
808
809
810 ipc->mutex_lock = g_mutex_new ();
811 ipc->transport = transport;
812 ipc->signals = ipc_object_pool->signals;
813 ipc->broadcasts = ipc_object_pool->broadcasts;
814 ipc->objects = ipc_object_pool->objects;
815
816 xmms_ipc_setup_server_internaly (ipc);
817 xmms_log_info ("IPC listening on '%s'.", split[i]);
818
819 g_mutex_lock (ipc_servers_lock);
820 ipc_servers = g_list_prepend (ipc_servers, ipc);
821 g_mutex_unlock (ipc_servers_lock);
822
823 num_init++;
824 }
825
826 g_strfreev (split);
827
828
829 /* If there is less than one socket, there is sth. wrong. */
830 if (num_init < 1)
831 return FALSE;
832
833 XMMS_DBG ("IPC setup done.");
834 return TRUE;
835}
836
837/** @} */
838
const gchar * xmms_config_property_get_string(const xmms_config_property_t *prop)
Return the value of a config property as a string.
Definition config.c:243
const gchar * xmms_error_message_get(xmms_error_t *err)
Get the human readable error.
Definition error.c:38
void xmms_ipc_object_unregister(xmms_ipc_objects_t objectid)
Remove a object from the IPC core.
Definition ipc.c:712
void xmms_ipc_signal_register(xmms_object_t *object, xmms_ipc_signals_t signalid)
Register a signal.
Definition ipc.c:669
gboolean xmms_ipc_has_pending(guint signalid)
Checks if someone is waiting for signalid.
Definition ipc.c:542
xmms_ipc_t * xmms_ipc_init()
Initialize IPC.
Definition ipc.c:5
void xmms_ipc_signal_unregister(xmms_ipc_signals_t signalid)
Unregister a signal.
Definition ipc.c:683
void xmms_ipc_broadcast_register(xmms_object_t *object, xmms_ipc_signals_t signalid)
Register a broadcast signal.
Definition ipc.c:637
void xmms_ipc_object_register(xmms_ipc_objects_t objectid, xmms_object_t *object)
Register a object to the IPC core.
Definition ipc.c:701
void on_config_ipcsocket_change(xmms_object_t *object, xmmsv_t *_data, gpointer udata)
Gets called when the config property "core.ipcsocket" has changed.
Definition ipc.c:438
void xmms_ipc_shutdown(void)
Disable IPC.
Definition ipc.c:765
gboolean xmms_ipc_setup_server(const gchar *path)
Start the server.
Definition ipc.c:785
void xmms_ipc_broadcast_unregister(xmms_ipc_signals_t signalid)
Unregister a broadcast signal.
Definition ipc.c:652
struct xmms_ipc_client_St xmms_ipc_client_t
A IPC client representation.
struct xmms_ipc_object_pool_t xmms_ipc_object_pool_t
The IPC object list.
int xmmsv_list_get(xmmsv_t *listv, int pos, xmmsv_t **val)
Get the element at the given position in the list xmmsv_t.
Definition value.c:1218
void xmms_object_disconnect(xmms_object_t *object, guint32 signalid, xmms_object_handler_t handler, gpointer userdata)
Disconnect from a signal.
Definition object.c:146
void xmms_object_cmd_arg_init(xmms_object_cmd_arg_t *arg)
Initialize a command argument.
Definition object.c:236
void xmms_object_connect(xmms_object_t *object, guint32 signalid, xmms_object_handler_t handler, gpointer userdata)
Connect to a signal that is emitted by this object.
Definition object.c:115
void xmms_object_cmd_call(xmms_object_t *object, guint cmdid, xmms_object_cmd_arg_t *arg)
Call a command with argument.
Definition object.c:338
void xmmsv_unref(xmmsv_t *val)
Decreases the references for the xmmsv_t When the number of references reaches 0 it will be freed.
Definition value.c:303
struct xmmsv_St xmmsv_t
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition value.c:823
xmmsv_t * xmmsv_new_error(const char *errstr)
Allocates a new error xmmsv_t.
Definition value.c:143
struct xmms_ipc_St xmms_ipc_t
Definition xmms_ipc.h:6
void xmms_set_thread_name(const gchar *name)
struct xmms_config_property_St xmms_config_property_t
Definition xmms_config.h:26
#define xmms_log_error(fmt,...)
Definition xmms_log.h:35
#define xmms_log_info(fmt,...)
Definition xmms_log.h:34
#define XMMS_DBG(fmt,...)
Definition xmms_log.h:32
#define xmms_error_isok(e)
Definition xmms_error.h:58
@ XMMS_IPC_CMD_ERROR
@ XMMS_IPC_CMD_REPLY
xmms_ipc_objects_t
@ XMMS_IPC_OBJECT_SIGNAL
@ XMMS_IPC_OBJECT_END
xmms_ipc_signals_t
@ XMMS_IPC_SIGNAL_END
@ XMMS_IPC_CMD_BROADCAST
@ XMMS_IPC_CMD_SIGNAL
void xmms_ipc_msg_destroy(xmms_ipc_msg_t *msg)
Definition msg.c:54
void xmms_ipc_msg_set_cookie(xmms_ipc_msg_t *msg, uint32_t cookie)
Definition msg.c:137
bool xmms_ipc_msg_get_value(xmms_ipc_msg_t *msg, xmmsv_t **val)
Definition msg.c:291
bool xmms_ipc_msg_write_transport(xmms_ipc_msg_t *msg, xmms_ipc_transport_t *transport, bool *disconnected)
Try to write message to transport.
Definition msg.c:180
uint32_t xmms_ipc_msg_get_cmd(const xmms_ipc_msg_t *msg)
Definition msg.c:114
uint32_t xmms_ipc_msg_get_object(const xmms_ipc_msg_t *msg)
Definition msg.c:91
bool xmms_ipc_msg_read_transport(xmms_ipc_msg_t *msg, xmms_ipc_transport_t *transport, bool *disconnected)
Try to read message from transport into msg.
Definition msg.c:226
uint32_t xmms_ipc_msg_put_value(xmms_ipc_msg_t *msg, xmmsv_t *v)
Definition msg.c:281
xmms_ipc_msg_t * xmms_ipc_msg_alloc(void)
Definition msg.c:41
xmms_ipc_msg_t * xmms_ipc_msg_new(uint32_t object, uint32_t cmd)
Definition msg.c:158
struct xmms_ipc_msg_St xmms_ipc_msg_t
uint32_t xmms_ipc_msg_get_cookie(const xmms_ipc_msg_t *msg)
Definition msg.c:145
void xmms_ipc_transport_destroy(xmms_ipc_transport_t *ipct)
Definition transport.c:27
xmms_socket_t xmms_ipc_transport_fd_get(xmms_ipc_transport_t *ipct)
Definition transport.c:49
xmms_ipc_transport_t * xmms_ipc_server_accept(xmms_ipc_transport_t *ipct)
Definition transport.c:56
xmms_ipc_transport_t * xmms_ipc_server_init(const char *path)