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  */
39 typedef struct xmms_ipc_object_pool_t {
44 
45 
46 /**
47  * The server IPC object
48  */
49 struct 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  */
63 typedef 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 
83 static GMutex *ipc_servers_lock;
84 static GList *ipc_servers = NULL;
85 
86 static GMutex *ipc_object_pool_lock;
87 static struct xmms_ipc_object_pool_t *ipc_object_pool = NULL;
88 
89 static void xmms_ipc_client_destroy (xmms_ipc_client_t *client);
90 
91 static void xmms_ipc_register_signal (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg, xmmsv_t *arguments);
92 static void xmms_ipc_register_broadcast (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg, xmmsv_t *arguments);
93 static gboolean xmms_ipc_client_msg_write (xmms_ipc_client_t *client, xmms_ipc_msg_t *msg);
94 
95 static void
96 xmms_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 
103 static void
104 xmms_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 
133 static void
134 xmms_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 
166 static void
167 process_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 
249 out:
250  if (arguments) {
251  xmmsv_unref (arguments);
252  }
253 }
254 
255 
256 static gboolean
257 xmms_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);
276  xmms_ipc_msg_destroy (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 
302 static gboolean
303 xmms_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 
337  xmms_ipc_msg_destroy (msg);
338  }
339 
340  return FALSE;
341 }
342 
343 static gpointer
344 xmms_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 
366 static xmms_ipc_client_t *
367 xmms_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 
399 static void
400 xmms_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);
420  xmms_ipc_msg_destroy (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  */
437 void
438 on_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  */
453 static gboolean
454 xmms_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 
482 static gboolean
483 xmms_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  */
522 static gboolean
523 xmms_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  */
541 gboolean
542 xmms_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 
570 static void
571 xmms_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 
602 static void
603 xmms_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  */
636 void
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  */
651 void
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  */
668 void
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  */
682 void
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  */
700 void
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  */
711 void
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  */
722 xmms_ipc_t *
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  */
734 static void
735 xmms_ipc_shutdown_server (xmms_ipc_t *ipc)
736 {
737  GList *c;
738  xmms_ipc_client_t *co;
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  */
764 void
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  */
784 gboolean
785 xmms_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 
#define xmms_error_isok(e)
Definition: xmms_error.h:58
xmms_ipc_t * xmms_ipc_init(void)
Initialize IPC.
Definition: ipc.c:723
void xmms_ipc_msg_set_cookie(xmms_ipc_msg_t *msg, uint32_t cookie)
Definition: msg.c:137
void xmms_set_thread_name(const gchar *name)
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
xmms_ipc_msg_t * xmms_ipc_msg_alloc(void)
Definition: msg.c:41
xmms_socket_t xmms_ipc_transport_fd_get(xmms_ipc_transport_t *ipct)
Definition: transport.c:49
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
gboolean xmms_ipc_has_pending(guint signalid)
Checks if someone is waiting for signalid.
Definition: ipc.c:542
xmmsv_t * xmmsv_new_error(const char *errstr)
Allocates a new error xmmsv_t.
Definition: value.c:143
bool xmms_ipc_msg_get_value(xmms_ipc_msg_t *msg, xmmsv_t **val)
Definition: msg.c:291
struct xmmsv_St xmmsv_t
Definition: xmmsv_general.h:48
uint32_t xmms_ipc_msg_get_cmd(const xmms_ipc_msg_t *msg)
Definition: msg.c:114
void xmms_ipc_broadcast_register(xmms_object_t *object, xmms_ipc_signals_t signalid)
Register a broadcast signal.
Definition: ipc.c:637
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition: value.c:823
gboolean xmms_ipc_setup_server(const gchar *path)
Start the server.
Definition: ipc.c:785
GTree * cmds
Definition: xmms_object.h:46
void xmms_ipc_signal_register(xmms_object_t *object, xmms_ipc_signals_t signalid)
Register a signal.
Definition: ipc.c:669
const gchar * xmms_error_message_get(xmms_error_t *err)
Get the human readable error.
Definition: error.c:38
void xmms_ipc_msg_destroy(xmms_ipc_msg_t *msg)
Definition: msg.c:54
struct xmms_ipc_msg_St xmms_ipc_msg_t
Definition: xmmsc_ipc_msg.h:31
struct xmms_ipc_client_St xmms_ipc_client_t
A IPC client representation.
xmms_ipc_msg_t * xmms_ipc_msg_new(uint32_t object, uint32_t cmd)
Definition: msg.c:158
#define xmms_log_error(fmt,...)
Definition: xmms_log.h:35
void xmms_object_cmd_arg_init(xmms_object_cmd_arg_t *arg)
Initialize a command argument.
Definition: object.c:236
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
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
xmms_ipc_objects_t
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
struct xmms_ipc_object_pool_t xmms_ipc_object_pool_t
The IPC object list.
xmms_ipc_transport_t * xmms_ipc_server_init(const char *path)
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
void xmms_ipc_signal_unregister(xmms_ipc_signals_t signalid)
Unregister a signal.
Definition: ipc.c:683
void xmms_ipc_object_unregister(xmms_ipc_objects_t objectid)
Remove a object from the IPC core.
Definition: ipc.c:712
xmms_ipc_transport_t * xmms_ipc_server_accept(xmms_ipc_transport_t *ipct)
Definition: transport.c:56
uint32_t xmms_ipc_msg_put_value(xmms_ipc_msg_t *msg, xmmsv_t *v)
Definition: msg.c:281
#define xmms_log_info(fmt,...)
Definition: xmms_log.h:34
xmms_ipc_signals_t
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_get_object(const xmms_ipc_msg_t *msg)
Definition: msg.c:91
void xmms_ipc_shutdown(void)
Disable IPC.
Definition: ipc.c:765
#define XMMS_DBG(fmt,...)
Definition: xmms_log.h:32
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
struct xmms_ipc_St xmms_ipc_t
Definition: xmms_ipc.h:6
void xmms_ipc_broadcast_unregister(xmms_ipc_signals_t signalid)
Unregister a broadcast signal.
Definition: ipc.c:652
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
struct xmms_config_property_St xmms_config_property_t
Definition: xmms_config.h:26
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
xmms_error_t error
Definition: xmms_object.h:72
void xmms_ipc_transport_destroy(xmms_ipc_transport_t *ipct)
Definition: transport.c:27
uint32_t xmms_ipc_msg_get_cookie(const xmms_ipc_msg_t *msg)
Definition: msg.c:145