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