XMMS2
msg.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 <stdarg.h>
18 #include <string.h>
19 #include <stdlib.h>
20 
21 #include <errno.h>
22 #include <time.h>
23 #include <assert.h>
24 
25 #include "xmmspriv/xmms_list.h"
27 #include "xmmsc/xmmsc_ipc_msg.h"
28 #include "xmmsc/xmmsc_util.h"
29 #include "xmmsc/xmmsc_sockets.h"
30 #include "xmmsc/xmmsc_stdint.h"
31 #include "xmmsc/xmmsv_coll.h"
32 
33 
34 typedef union {
35  struct {
36  uint32_t object;
37  uint32_t cmd;
38  uint32_t cookie;
39  uint32_t length;
40  uint8_t data[0];
41  } header;
42  uint8_t rawdata[0];
43 } xmms_ipc_msg_data_t;
44 
45 struct xmms_ipc_msg_St {
46  xmms_ipc_msg_data_t *data;
47  uint32_t get_pos;
48  uint32_t size;
49  uint32_t xfered;
50 };
51 
52 static void xmms_ipc_msg_store_uint32 (xmms_ipc_msg_t *msg, uint32_t offset, uint32_t v);
53 
54 static uint32_t internal_ipc_msg_put_bin (xmms_ipc_msg_t *msg, const unsigned char *data, unsigned int len);
55 static uint32_t internal_ipc_msg_put_error (xmms_ipc_msg_t *msg, const char *errmsg);
56 static uint32_t internal_ipc_msg_put_uint32 (xmms_ipc_msg_t *msg, uint32_t v);
57 static uint32_t internal_ipc_msg_put_int32 (xmms_ipc_msg_t *msg, int32_t v);
58 static uint32_t internal_ipc_msg_put_string (xmms_ipc_msg_t *msg, const char *str);
59 static uint32_t internal_ipc_msg_put_collection (xmms_ipc_msg_t *msg, xmmsv_coll_t *coll);
60 static uint32_t internal_ipc_msg_put_value_list (xmms_ipc_msg_t *msg, xmmsv_t *v);
61 static uint32_t internal_ipc_msg_put_value_dict (xmms_ipc_msg_t *msg, xmmsv_t *v);
62 
63 static bool xmms_ipc_msg_get_error_alloc (xmms_ipc_msg_t *msg, char **buf, unsigned int *len);
64 static bool xmms_ipc_msg_get_uint32 (xmms_ipc_msg_t *msg, uint32_t *v);
65 static bool xmms_ipc_msg_get_int32 (xmms_ipc_msg_t *msg, int32_t *v);
66 static bool xmms_ipc_msg_get_string_alloc (xmms_ipc_msg_t *msg, char **buf, unsigned int *len);
67 static bool xmms_ipc_msg_get_collection_alloc (xmms_ipc_msg_t *msg, xmmsv_coll_t **coll);
68 static bool xmms_ipc_msg_get_bin_alloc (xmms_ipc_msg_t *msg, unsigned char **buf, unsigned int *len);
69 
70 static bool xmms_ipc_msg_get_value_alloc (xmms_ipc_msg_t *msg, xmmsv_t **val);
71 static bool xmms_ipc_msg_get_value_of_type_alloc (xmms_ipc_msg_t *msg, xmmsv_type_t type, xmmsv_t **val);
72 
73 static void
74 xmms_ipc_append_coll_attr (const char *key, xmmsv_t *value, void *userdata)
75 {
76  xmms_ipc_msg_t *msg = (xmms_ipc_msg_t *)userdata;
77  const char *s;
78  int r;
79 
80  r = xmmsv_get_string (value, &s);
81  x_return_if_fail (r);
82 
83  internal_ipc_msg_put_string (msg, key);
84  internal_ipc_msg_put_string (msg, s);
85 }
86 
87 static void
88 xmms_ipc_count_coll_attr (const char *key, xmmsv_t *value, void *userdata)
89 {
90  int *n = (int *)userdata;
91  ++(*n);
92 }
93 
94 
97 {
98  xmms_ipc_msg_t *msg;
99 
100  msg = x_new0 (xmms_ipc_msg_t, 1);
101  msg->data = malloc (XMMS_IPC_MSG_DEFAULT_SIZE);
102  memset (msg->data, 0, XMMS_IPC_MSG_HEAD_LEN);
103  msg->size = XMMS_IPC_MSG_DEFAULT_SIZE;
104 
105  return msg;
106 }
107 
109 xmms_ipc_msg_new (uint32_t object, uint32_t cmd)
110 {
111  xmms_ipc_msg_t *msg;
112 
113  msg = xmms_ipc_msg_alloc ();
114 
115  xmms_ipc_msg_set_cmd (msg, cmd);
116  xmms_ipc_msg_set_object (msg, object);
117 
118  return msg;
119 }
120 
121 void
123 {
124  x_return_if_fail (msg);
125 
126  free (msg->data);
127  free (msg);
128 }
129 
130 void
132 {
133  x_return_if_fail (msg);
134 
135  msg->data->header.length = htonl (len);
136 }
137 
138 uint32_t
140 {
141  x_return_val_if_fail (msg, 0);
142 
143  return ntohl (msg->data->header.length);
144 }
145 
146 uint32_t
148 {
149  x_return_val_if_fail (msg, 0);
150 
151  return ntohl (msg->data->header.object);
152 }
153 
154 void
156 {
157  x_return_if_fail (msg);
158 
159  msg->data->header.object = htonl (object);
160 }
161 
162 uint32_t
164 {
165  x_return_val_if_fail (msg, 0);
166 
167  return ntohl (msg->data->header.cmd);
168 }
169 
170 void
172 {
173  x_return_if_fail (msg);
174 
175  msg->data->header.cmd = htonl (cmd);
176 }
177 
178 void
180 {
181  msg->data->header.cookie = htonl (cookie);
182 }
183 
184 uint32_t
186 {
187  x_return_val_if_fail (msg, 0);
188 
189  return ntohl (msg->data->header.cookie);
190 }
191 
192 /**
193  * Try to write message to transport. If full message isn't written
194  * the message will keep track of the amount of data written and not
195  * write already written data next time.
196  *
197  * @returns TRUE if full message was written, FALSE otherwise.
198  * disconnected is set if transport was disconnected
199  */
200 bool
202  xmms_ipc_transport_t *transport,
203  bool *disconnected)
204 {
205  char *buf;
206  unsigned int ret, len;
207 
208  x_return_val_if_fail (msg, false);
209  x_return_val_if_fail (msg->data, false);
210  x_return_val_if_fail (transport, false);
211 
213 
214  x_return_val_if_fail (len > msg->xfered, true);
215 
216  buf = (char *) (msg->data->rawdata + msg->xfered);
217  ret = xmms_ipc_transport_write (transport, buf, len - msg->xfered);
218 
219  if (ret == SOCKET_ERROR) {
221  return false;
222  }
223 
224  if (disconnected) {
225  *disconnected = true;
226  }
227 
228  return false;
229  } else if (!ret) {
230  if (disconnected) {
231  *disconnected = true;
232  }
233  } else {
234  msg->xfered += ret;
235  }
236 
237  return (len == msg->xfered);
238 }
239 
240 /**
241  * Try to read message from transport into msg.
242  *
243  * @returns TRUE if message is fully read.
244  */
245 bool
247  xmms_ipc_transport_t *transport,
248  bool *disconnected)
249 {
250  char *buf;
251  unsigned int ret, len;
252 
253  x_return_val_if_fail (msg, false);
254  x_return_val_if_fail (transport, false);
255 
256  while (true) {
257  len = XMMS_IPC_MSG_HEAD_LEN;
258 
259  if (msg->xfered >= XMMS_IPC_MSG_HEAD_LEN) {
260  len += xmms_ipc_msg_get_length (msg);
261 
262  if (len > msg->size) {
263  void *newbuf;
264  newbuf = realloc (msg->data, len);
265  if (!newbuf) {
266  if (disconnected) {
267  *disconnected = true;
268  }
269  return false;
270  }
271  msg->size = len;
272  msg->data = newbuf;
273  }
274 
275  if (msg->xfered == len) {
276  return true;
277  }
278  }
279 
280  x_return_val_if_fail (msg->xfered < len, false);
281 
282  buf = (char *) (msg->data->rawdata + msg->xfered);
283  ret = xmms_ipc_transport_read (transport, buf, len - msg->xfered);
284 
285  if (ret == SOCKET_ERROR) {
287  return false;
288  }
289 
290  if (disconnected) {
291  *disconnected = true;
292  }
293 
294  return false;
295  } else if (ret == 0) {
296  if (disconnected) {
297  *disconnected = true;
298  }
299 
300  return false;
301  } else {
302  msg->xfered += ret;
303  }
304  }
305 }
306 
307 static uint32_t
308 xmms_ipc_msg_put_data (xmms_ipc_msg_t *msg, const void *data, unsigned int len)
309 {
310  uint32_t total;
311 
312  x_return_val_if_fail (msg, -1);
313 
314  total = xmms_ipc_msg_get_length (msg) + XMMS_IPC_MSG_HEAD_LEN + len;
315 
316  if (total > msg->size) {
317  int realloc_size = XMMS_IPC_MSG_DEFAULT_SIZE;
318 
319  if (len > XMMS_IPC_MSG_DEFAULT_SIZE) {
320  realloc_size = len;
321  }
322 
323  /* Realloc data portion */
324  msg->data = realloc (msg->data, msg->size + realloc_size);
325  msg->size += realloc_size;
326  }
327 
328  total = xmms_ipc_msg_get_length (msg);
329  memcpy (&msg->data->header.data[total], data, len);
330  xmms_ipc_msg_set_length (msg, total + len);
331 
332  /* return the offset that which we placed this value.
333  * If this logic is changed, make sure to update
334  * the return value of xmms_ipc_msg_put_value_data for
335  * NONE xmmsv's, too.
336  */
337  return total;
338 }
339 
340 static uint32_t
341 internal_ipc_msg_put_bin (xmms_ipc_msg_t *msg,
342  const unsigned char *data,
343  unsigned int len)
344 {
345  internal_ipc_msg_put_uint32 (msg, len);
346 
347  return xmms_ipc_msg_put_data (msg, data, len);
348 }
349 
350 static uint32_t
351 internal_ipc_msg_put_error (xmms_ipc_msg_t *msg, const char *errmsg)
352 {
353  if (!msg) {
354  return -1;
355  }
356 
357  if (!errmsg) {
358  return internal_ipc_msg_put_uint32 (msg, 0);
359  }
360 
361  internal_ipc_msg_put_uint32 (msg, strlen (errmsg) + 1);
362 
363  return xmms_ipc_msg_put_data (msg, errmsg, strlen (errmsg) + 1);
364 }
365 
366 static uint32_t
367 internal_ipc_msg_put_uint32 (xmms_ipc_msg_t *msg, uint32_t v)
368 {
369  v = htonl (v);
370 
371  return xmms_ipc_msg_put_data (msg, &v, sizeof (v));
372 }
373 
374 static void
375 xmms_ipc_msg_store_uint32 (xmms_ipc_msg_t *msg,
376  uint32_t offset, uint32_t v)
377 {
378  v = htonl (v);
379 
380  memcpy (&msg->data->header.data[offset], &v, sizeof (v));
381 }
382 
383 static uint32_t
384 internal_ipc_msg_put_int32 (xmms_ipc_msg_t *msg, int32_t v)
385 {
386  v = htonl (v);
387 
388  return xmms_ipc_msg_put_data (msg, &v, sizeof (v));
389 }
390 
391 static uint32_t
392 internal_ipc_msg_put_string (xmms_ipc_msg_t *msg, const char *str)
393 {
394  if (!msg) {
395  return -1;
396  }
397 
398  if (!str) {
399  return internal_ipc_msg_put_uint32 (msg, 0);
400  }
401 
402  internal_ipc_msg_put_uint32 (msg, strlen (str) + 1);
403 
404  return xmms_ipc_msg_put_data (msg, str, strlen (str) + 1);
405 }
406 
407 static uint32_t
408 internal_ipc_msg_put_collection (xmms_ipc_msg_t *msg, xmmsv_coll_t *coll)
409 {
410  xmmsv_list_iter_t *it;
411  xmmsv_t *v, *attrs;
412  int n;
413  uint32_t ret, *idlist;
414  xmmsv_coll_t *op;
415 
416  if (!msg || !coll) {
417  return -1;
418  }
419 
420  /* push type */
421  internal_ipc_msg_put_uint32 (msg, xmmsv_coll_get_type (coll));
422 
423  /* attribute counter and values */
424  attrs = xmmsv_coll_attributes_get (coll);
425  n = 0;
426 
427  xmmsv_dict_foreach (attrs, xmms_ipc_count_coll_attr, &n);
428  internal_ipc_msg_put_uint32 (msg, n);
429 
430  xmmsv_dict_foreach (attrs, xmms_ipc_append_coll_attr, msg);
431 
432  attrs = NULL; /* no unref needed. */
433 
434  /* idlist counter and content */
435  idlist = xmmsv_coll_get_idlist (coll);
436  for (n = 0; idlist[n] != 0; n++) { }
437 
438  internal_ipc_msg_put_uint32 (msg, n);
439  for (n = 0; idlist[n] != 0; n++) {
440  internal_ipc_msg_put_uint32 (msg, idlist[n]);
441  }
442 
443  /* operands counter and objects */
444  n = 0;
447  }
448 
449  ret = internal_ipc_msg_put_uint32 (msg, n);
450 
451  if (n > 0) {
453 
454  while (xmmsv_list_iter_entry (it, &v)) {
455  if (!xmmsv_get_coll (v, &op)) {
456  x_api_error ("Non collection operand", 0);
457  }
458 
459  internal_ipc_msg_put_int32 (msg, XMMSV_TYPE_COLL);
460 
461  ret = internal_ipc_msg_put_collection (msg, op);
463  }
464  }
465 
466  return ret;
467 }
468 
469 uint32_t
471 {
472  uint32_t ret;
473  int32_t i;
474  const char *s;
475  xmmsv_coll_t *c;
476  const unsigned char *bc;
477  unsigned int bl;
478  xmmsv_type_t type;
479 
480  type = xmmsv_get_type (v);
481  internal_ipc_msg_put_int32 (msg, type);
482 
483  /* FIXME: what to do if value fetching fails? */
484  /* FIXME: return -1 unsigned int?? */
485 
486  switch (type) {
487  case XMMSV_TYPE_ERROR:
488  if (!xmmsv_get_error (v, &s)) {
489  return -1;
490  }
491  ret = internal_ipc_msg_put_error (msg, s);
492  break;
493  case XMMSV_TYPE_INT32:
494  if (!xmmsv_get_int (v, &i)) {
495  return -1;
496  }
497  ret = internal_ipc_msg_put_int32 (msg, i);
498  break;
499  case XMMSV_TYPE_STRING:
500  if (!xmmsv_get_string (v, &s)) {
501  return -1;
502  }
503  ret = internal_ipc_msg_put_string (msg, s);
504  break;
505  case XMMSV_TYPE_COLL:
506  if (!xmmsv_get_coll (v, &c)) {
507  return -1;
508  }
509  ret = internal_ipc_msg_put_collection (msg, c);
510  break;
511  case XMMSV_TYPE_BIN:
512  if (!xmmsv_get_bin (v, &bc, &bl)) {
513  return -1;
514  }
515  ret = internal_ipc_msg_put_bin (msg, bc, bl);
516  break;
517  case XMMSV_TYPE_LIST:
518  ret = internal_ipc_msg_put_value_list (msg, v);
519  break;
520  case XMMSV_TYPE_DICT:
521  ret = internal_ipc_msg_put_value_dict (msg, v);
522  break;
523 
524  case XMMSV_TYPE_NONE:
525  /* just like the other _put_* functions, we
526  * return the offset that which we placed this value.
527  * See xmms_ipc_msg_put_data().
528  */
529  ret = xmms_ipc_msg_get_length (msg);
530  break;
531  default:
532  x_internal_error ("Tried to serialize value of unsupported type");
533  return -1;
534  }
535 
536  return ret;
537 }
538 
539 static uint32_t
540 internal_ipc_msg_put_value_list (xmms_ipc_msg_t *msg, xmmsv_t *v)
541 {
542  xmmsv_list_iter_t *it;
543  xmmsv_t *entry;
544  uint32_t ret, offset, count;
545 
546  if (!xmmsv_get_list_iter (v, &it)) {
547  return -1;
548  }
549 
550  /* store a dummy value, store the real count once it's known */
551  offset = internal_ipc_msg_put_uint32 (msg, 0);
552 
553  count = 0;
554  while (xmmsv_list_iter_valid (it)) {
555  xmmsv_list_iter_entry (it, &entry);
556  ret = xmms_ipc_msg_put_value (msg, entry);
558  count++;
559  }
560 
561  /* overwrite with real size */
562  xmms_ipc_msg_store_uint32 (msg, offset, count);
563 
564  return ret;
565 }
566 
567 static uint32_t
568 internal_ipc_msg_put_value_dict (xmms_ipc_msg_t *msg, xmmsv_t *v)
569 {
570  xmmsv_dict_iter_t *it;
571  const char *key;
572  xmmsv_t *entry;
573  uint32_t ret, offset, count;
574 
575  if (!xmmsv_get_dict_iter (v, &it)) {
576  return -1;
577  }
578 
579  /* store a dummy value, store the real count once it's known */
580  offset = internal_ipc_msg_put_uint32 (msg, 0);
581 
582  count = 0;
583  while (xmmsv_dict_iter_valid (it)) {
584  xmmsv_dict_iter_pair (it, &key, &entry);
585  ret = internal_ipc_msg_put_string (msg, key);
586  ret = xmms_ipc_msg_put_value (msg, entry);
588  count++;
589  }
590 
591  /* overwrite with real size */
592  xmms_ipc_msg_store_uint32 (msg, offset, count);
593 
594  return ret;
595 }
596 
597 
598 static bool
599 xmms_ipc_msg_get_data (xmms_ipc_msg_t *msg, void *buf, unsigned int len)
600 {
601  if (!msg)
602  return false;
603 
604  if (len > xmms_ipc_msg_get_length (msg) - msg->get_pos)
605  return false;
606 
607  if (buf) {
608  memcpy (buf, &msg->data->header.data[msg->get_pos], len);
609  }
610 
611  msg->get_pos += len;
612 
613  return true;
614 }
615 
616 static bool
617 xmms_ipc_msg_get_error_alloc (xmms_ipc_msg_t *msg, char **buf,
618  unsigned int *len)
619 {
620  /* currently, an error is just a string, so reuse that */
621  return xmms_ipc_msg_get_string_alloc (msg, buf, len);
622 }
623 
624 static bool
625 xmms_ipc_msg_get_uint32 (xmms_ipc_msg_t *msg, uint32_t *v)
626 {
627  bool ret;
628 
629  ret = xmms_ipc_msg_get_data (msg, v, sizeof (*v));
630 
631  if (v) {
632  *v = ntohl (*v);
633  }
634 
635  return ret;
636 }
637 
638 static bool
639 xmms_ipc_msg_get_int32 (xmms_ipc_msg_t *msg, int32_t *v)
640 {
641  bool ret;
642 
643  ret = xmms_ipc_msg_get_data (msg, v, sizeof (*v));
644 
645  if (v) {
646  *v = ntohl (*v);
647  }
648 
649  return ret;
650 }
651 
652 static bool
653 xmms_ipc_msg_get_string_alloc (xmms_ipc_msg_t *msg, char **buf,
654  unsigned int *len)
655 {
656  char *str;
657  unsigned int l;
658 
659  if (!xmms_ipc_msg_get_uint32 (msg, &l)) {
660  return false;
661  }
662 
663  if (l > xmms_ipc_msg_get_length (msg) - msg->get_pos)
664  return false;
665 
666  str = x_malloc (l + 1);
667  if (!str) {
668  return false;
669  }
670 
671  if (!xmms_ipc_msg_get_data (msg, str, l)) {
672  free (str);
673  return false;
674  }
675 
676  str[l] = '\0';
677 
678  *buf = str;
679  *len = l;
680 
681  return true;
682 }
683 
684 static bool
685 xmms_ipc_msg_get_bin_alloc (xmms_ipc_msg_t *msg,
686  unsigned char **buf,
687  unsigned int *len)
688 {
689  unsigned char *b;
690  unsigned int l;
691 
692  if (!xmms_ipc_msg_get_uint32 (msg, &l)) {
693  return false;
694  }
695 
696  if (l > xmms_ipc_msg_get_length (msg) - msg->get_pos)
697  return false;
698 
699  b = x_malloc (l);
700  if (!b) {
701  return false;
702  }
703 
704  if (!xmms_ipc_msg_get_data (msg, b, l)) {
705  free (b);
706  return false;
707  }
708 
709  *buf = b;
710  *len = l;
711 
712  return true;
713 }
714 
715 static bool
716 xmms_ipc_msg_get_collection_alloc (xmms_ipc_msg_t *msg, xmmsv_coll_t **coll)
717 {
718  unsigned int i;
719  unsigned int type;
720  unsigned int n_items;
721  unsigned int id;
722  uint32_t *idlist = NULL;
723  char *key, *val;
724 
725  /* Get the type and create the collection */
726  if (!xmms_ipc_msg_get_uint32 (msg, &type)) {
727  return false;
728  }
729 
730  *coll = xmmsv_coll_new (type);
731 
732  /* Get the list of attributes */
733  if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
734  goto err;
735  }
736 
737  for (i = 0; i < n_items; i++) {
738  unsigned int len;
739  if (!xmms_ipc_msg_get_string_alloc (msg, &key, &len)) {
740  goto err;
741  }
742  if (!xmms_ipc_msg_get_string_alloc (msg, &val, &len)) {
743  free (key);
744  goto err;
745  }
746 
747  xmmsv_coll_attribute_set (*coll, key, val);
748  free (key);
749  free (val);
750  }
751 
752  /* Get the idlist */
753  if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
754  goto err;
755  }
756 
757  if (!(idlist = x_new (uint32_t, n_items + 1))) {
758  goto err;
759  }
760 
761  for (i = 0; i < n_items; i++) {
762  if (!xmms_ipc_msg_get_uint32 (msg, &id)) {
763  goto err;
764  }
765 
766  idlist[i] = id;
767  }
768 
769  idlist[i] = 0;
770  xmmsv_coll_set_idlist (*coll, idlist);
771  free (idlist);
772  idlist = NULL;
773 
774  /* Get the operands */
775  if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
776  goto err;
777  }
778 
779  for (i = 0; i < n_items; i++) {
780  xmmsv_coll_t *operand;
781  xmmsv_type_t type;
782 
783  if (!xmms_ipc_msg_get_uint32 (msg, &type) ||
784  type != XMMSV_TYPE_COLL ||
785  !xmms_ipc_msg_get_collection_alloc (msg, &operand)) {
786  goto err;
787  }
788 
789  xmmsv_coll_add_operand (*coll, operand);
790  xmmsv_coll_unref (operand);
791  }
792 
793  return true;
794 
795 err:
796  if (idlist != NULL) {
797  free (idlist);
798  }
799 
800  xmmsv_coll_unref (*coll);
801 
802  return false;
803 }
804 
805 
806 static int
807 xmmsc_deserialize_dict (xmms_ipc_msg_t *msg, xmmsv_t **val)
808 {
809  xmmsv_t *dict;
810  unsigned int len, ignore;
811  char *key;
812 
813  dict = xmmsv_new_dict ();
814 
815  if (!xmms_ipc_msg_get_uint32 (msg, &len)) {
816  goto err;
817  }
818 
819  while (len--) {
820  xmmsv_t *v;
821 
822  if (!xmms_ipc_msg_get_string_alloc (msg, &key, &ignore)) {
823  goto err;
824  }
825 
826  if (!xmms_ipc_msg_get_value_alloc (msg, &v)) {
827  free (key);
828  goto err;
829  }
830 
831  xmmsv_dict_set (dict, key, v);
832  free (key);
833  xmmsv_unref (v);
834  }
835 
836  *val = dict;
837 
838  return true;
839 
840 err:
841  x_internal_error ("Message from server did not parse correctly!");
842  xmmsv_unref (dict);
843  return false;
844 }
845 
846 static int
847 xmmsc_deserialize_list (xmms_ipc_msg_t *msg, xmmsv_t **val)
848 {
849  xmmsv_t *list;
850  unsigned int len;
851 
852  list = xmmsv_new_list ();
853 
854  if (!xmms_ipc_msg_get_uint32 (msg, &len)) {
855  goto err;
856  }
857 
858  while (len--) {
859  xmmsv_t *v;
860  if (xmms_ipc_msg_get_value_alloc (msg, &v)) {
861  xmmsv_list_append (list, v);
862  } else {
863  goto err;
864  }
865  xmmsv_unref (v);
866  }
867 
868  *val = list;
869 
870  return true;
871 
872 err:
873  x_internal_error ("Message from server did not parse correctly!");
874  xmmsv_unref (list);
875  return false;
876 }
877 
878 static bool
879 xmms_ipc_msg_get_value_alloc (xmms_ipc_msg_t *msg, xmmsv_t **val)
880 {
881  int32_t type;
882 
883  if (!xmms_ipc_msg_get_int32 (msg, &type)) {
884  return false;
885  }
886 
887  return xmms_ipc_msg_get_value_of_type_alloc (msg, type, val);
888 }
889 
890 static bool
891 xmms_ipc_msg_get_value_of_type_alloc (xmms_ipc_msg_t *msg, xmmsv_type_t type,
892  xmmsv_t **val)
893 {
894  int32_t i;
895  uint32_t len;
896  char *s;
897  xmmsv_coll_t *c;
898  unsigned char *d;
899 
900  switch (type) {
901  case XMMSV_TYPE_ERROR:
902  if (!xmms_ipc_msg_get_error_alloc (msg, &s, &len)) {
903  return false;
904  }
905  *val = xmmsv_new_error (s);
906  free (s);
907  break;
908  case XMMSV_TYPE_INT32:
909  if (!xmms_ipc_msg_get_int32 (msg, &i)) {
910  return false;
911  }
912  *val = xmmsv_new_int (i);
913  break;
914  case XMMSV_TYPE_STRING:
915  if (!xmms_ipc_msg_get_string_alloc (msg, &s, &len)) {
916  return false;
917  }
918  *val = xmmsv_new_string (s);
919  free (s);
920  break;
921  case XMMSV_TYPE_DICT:
922  if (!xmmsc_deserialize_dict (msg, val)) {
923  return false;
924  }
925  break;
926 
927  case XMMSV_TYPE_LIST :
928  if (!xmmsc_deserialize_list (msg, val)) {
929  return false;
930  }
931  break;
932 
933  case XMMSV_TYPE_COLL:
934  if (!xmms_ipc_msg_get_collection_alloc (msg, &c)) {
935  return false;
936  }
937  *val = xmmsv_new_coll (c);
938  xmmsv_coll_unref (c);
939  break;
940 
941  case XMMSV_TYPE_BIN:
942  if (!xmms_ipc_msg_get_bin_alloc (msg, &d, &len)) {
943  return false;
944  }
945  *val = xmmsv_new_bin (d, len);
946  free (d);
947  break;
948 
949  case XMMSV_TYPE_NONE:
950  *val = xmmsv_new_none ();
951  break;
952  default:
953  x_internal_error ("Got message of unknown type!");
954  return false;
955  }
956 
957  return true;
958 }
959 
960 bool
962 {
963  return xmms_ipc_msg_get_value_alloc (msg, val);
964 }
struct xmmsv_St xmmsv_t
Definition: xmmsv.h:51
xmmsv_t * xmmsv_new_dict(void)
Allocates a new dict xmmsv_t.
Definition: value.c:266
int xmms_ipc_transport_read(xmms_ipc_transport_t *ipct, char *buffer, int len)
Definition: transport.c:37
#define XMMS_IPC_MSG_HEAD_LEN
Definition: xmmsc_ipc_msg.h:29
#define x_return_val_if_fail(expr, val)
Definition: xmmsc_util.h:12
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
int xmmsv_dict_set(xmmsv_t *dictv, const char *key, xmmsv_t *val)
Insert an element under the given key in the dict xmmsv_t.
Definition: value.c:1744
bool xmms_socket_error_recoverable(void)
Definition: socket_common.c:9
xmms_ipc_msg_t * xmms_ipc_msg_alloc(void)
Definition: msg.c:96
int xmmsv_dict_iter_valid(xmmsv_dict_iter_t *it)
Check whether the iterator is valid and points to a valid pair.
Definition: value.c:1975
int xmmsv_get_list_iter(const xmmsv_t *val, xmmsv_list_iter_t **it)
Retrieves a list iterator from a list xmmsv_t.
Definition: value.c:918
xmmsv_t * xmmsv_new_error(const char *errstr)
Allocates a new error xmmsv_t.
Definition: value.c:141
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
int xmmsv_list_iter_entry(xmmsv_list_iter_t *it, xmmsv_t **val)
Get the element currently pointed at by the iterator.
Definition: value.c:1487
uint32_t xmms_ipc_msg_get_cmd(const xmms_ipc_msg_t *msg)
Definition: msg.c:163
#define x_malloc(size)
Definition: xmmsc_util.h:18
void xmmsv_coll_attribute_set(xmmsv_coll_t *coll, const char *key, const char *value)
Set an attribute in the given collection.
Definition: coll.c:512
xmmsv_t * xmmsv_new_string(const char *s)
Allocates a new string xmmsv_t.
Definition: value.c:178
int xmmsv_get_int(const xmmsv_t *val, int32_t *r)
Retrieves a signed integer from the value.
Definition: value.c:815
int xmmsv_list_append(xmmsv_t *listv, xmmsv_t *val)
Append an element to the end of the list xmmsv_t.
Definition: value.c:1332
#define XMMS_IPC_MSG_DEFAULT_SIZE
Definition: xmmsc_ipc_msg.h:28
struct xmmsv_St * xmmsv_coll_operands_get(xmmsv_coll_t *coll)
Definition: coll.c:489
void xmms_ipc_msg_set_cmd(xmms_ipc_msg_t *msg, uint32_t cmd)
Definition: msg.c:171
void xmms_ipc_msg_destroy(xmms_ipc_msg_t *msg)
Definition: msg.c:122
int xmmsv_dict_foreach(xmmsv_t *dictv, xmmsv_dict_foreach_func func, void *user_data)
Apply a function to each key-element pair in the list.
Definition: value.c:1845
struct xmms_ipc_msg_St xmms_ipc_msg_t
Definition: xmmsc_ipc_msg.h:31
xmms_ipc_msg_t * xmms_ipc_msg_new(uint32_t object, uint32_t cmd)
Definition: msg.c:109
int xmmsv_get_coll(const xmmsv_t *val, xmmsv_coll_t **coll)
Retrieves a collection from the value.
Definition: value.c:875
int xmmsv_dict_iter_pair(xmmsv_dict_iter_t *it, const char **key, xmmsv_t **val)
Get the key-element pair currently pointed at by the iterator.
Definition: value.c:1940
xmmsv_t * xmmsv_new_coll(xmmsv_coll_t *coll)
Allocates a new collection xmmsv_t.
Definition: value.c:200
void xmms_ipc_msg_set_object(xmms_ipc_msg_t *msg, uint32_t object)
Definition: msg.c:155
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
uint32_t xmms_ipc_msg_get_length(const xmms_ipc_msg_t *msg)
Definition: msg.c:139
struct xmmsv_coll_St xmmsv_coll_t
Definition: xmmsv_coll.h:28
int xmmsv_list_get_size(xmmsv_t *listv)
Return the size of the list.
Definition: value.c:1395
#define x_new(type, num)
Definition: xmmsc_util.h:16
xmmsv_type_t
Definition: xmmsv.h:29
void xmmsv_list_iter_next(xmmsv_list_iter_t *it)
Advance the iterator to the next element in the list.
Definition: value.c:1545
xmmsv_coll_t * xmmsv_coll_new(xmmsv_coll_type_t type)
Allocate a new collection of the given type.
Definition: coll.c:83
xmmsv_type_t xmmsv_get_type(const xmmsv_t *val)
Get the type of the value.
Definition: value.c:384
xmmsv_t * xmmsv_new_int(int32_t i)
Allocates a new integer xmmsv_t.
Definition: value.c:159
int xmms_ipc_transport_write(xmms_ipc_transport_t *ipct, char *buffer, int len)
Definition: transport.c:43
struct xmmsv_St * xmmsv_coll_attributes_get(xmmsv_coll_t *coll)
Definition: coll.c:497
void xmmsv_coll_add_operand(xmmsv_coll_t *coll, xmmsv_coll_t *op)
Add the operand to the given collection.
Definition: coll.c:218
int xmmsv_get_error(const xmmsv_t *val, const char **r)
Retrieves an error string describing the server error from the value.
Definition: value.c:796
void xmmsv_dict_iter_next(xmmsv_dict_iter_t *it)
Advance the iterator to the next pair in the dict.
Definition: value.c:2001
uint32_t xmms_ipc_msg_put_value(xmms_ipc_msg_t *msg, xmmsv_t *v)
Definition: msg.c:470
void xmmsv_coll_set_idlist(xmmsv_coll_t *coll, unsigned int ids[])
Set the list of ids in the given collection.
Definition: coll.c:168
#define x_new0(type, num)
Definition: xmmsc_util.h:15
#define SOCKET_ERROR
Definition: xmmsc_sockets.h:17
xmmsv_t * xmmsv_new_bin(unsigned char *data, unsigned int len)
Allocates a new binary data xmmsv_t.
Definition: value.c:223
int xmmsv_get_dict_iter(const xmmsv_t *val, xmmsv_dict_iter_t **it)
Retrieves a dict iterator from a dict xmmsv_t.
Definition: value.c:947
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
int xmmsv_get_bin(const xmmsv_t *val, const unsigned char **r, unsigned int *rlen)
Retrieves binary data from the value.
Definition: value.c:896
xmmsv_t * xmmsv_new_list(void)
Allocates a new list xmmsv_t.
Definition: value.c:248
#define x_return_if_fail(expr)
Definition: xmmsc_util.h:11
int xmmsv_get_string(const xmmsv_t *val, const char **r)
Retrieves a string from the value.
Definition: value.c:855
void xmms_ipc_msg_set_length(xmms_ipc_msg_t *msg, uint32_t len)
Definition: msg.c:131
uint32_t * xmmsv_coll_get_idlist(xmmsv_coll_t *coll)
Return the list of ids stored in the collection.
Definition: coll.c:481
xmmsv_coll_type_t xmmsv_coll_get_type(xmmsv_coll_t *coll)
Return the type of the collection.
Definition: coll.c:464
struct xmmsv_list_iter_St xmmsv_list_iter_t
Definition: xmmsv.h:53
int xmmsv_list_iter_valid(xmmsv_list_iter_t *it)
Check whether the iterator is valid and points to a valid element.
Definition: value.c:1504
void xmmsv_coll_unref(xmmsv_coll_t *coll)
Decreases the references for the xmmsv_coll_t When the number of references reaches 0 it will be free...
Definition: coll.c:147
uint32_t xmms_ipc_msg_get_cookie(const xmms_ipc_msg_t *msg)
Definition: msg.c:185
struct xmmsv_dict_iter_St xmmsv_dict_iter_t
Definition: xmmsv.h:54