00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017 #include <stdarg.h>
00018 #include <string.h>
00019 #include <stdlib.h>
00020
00021 #include <errno.h>
00022 #include <time.h>
00023
00024 #include "xmmsc/xmmsc_ipc_transport.h"
00025 #include "xmmsc/xmmsc_ipc_msg.h"
00026 #include "xmmsc/xmmsc_util.h"
00027 #include "xmmsc/xmmsc_sockets.h"
00028 #include "xmmsc/xmmsc_stdint.h"
00029 #include "xmmsc/xmmsc_coll.h"
00030
00031 typedef union {
00032 struct {
00033 uint32_t object;
00034 uint32_t cmd;
00035 uint32_t cookie;
00036 uint32_t length;
00037 uint8_t data[0];
00038 } header;
00039 uint8_t rawdata[0];
00040 } xmms_ipc_msg_data_t;
00041
00042 struct xmms_ipc_msg_St {
00043 xmms_ipc_msg_data_t *data;
00044 uint32_t get_pos;
00045 uint32_t size;
00046 uint32_t xfered;
00047 };
00048
00049
00050 void
00051 xmms_ipc_append_coll_attr (const char* key, const char* value, void *userdata) {
00052 xmms_ipc_msg_t *msg = (xmms_ipc_msg_t *)userdata;
00053 xmms_ipc_msg_put_string (msg, key);
00054 xmms_ipc_msg_put_string (msg, value);
00055 }
00056
00057 void
00058 xmms_ipc_count_coll_attr (const char* key, const char* value, void *userdata) {
00059 int *n = (int *)userdata;
00060 ++(*n);
00061 }
00062
00063
00064 xmms_ipc_msg_t *
00065 xmms_ipc_msg_alloc (void)
00066 {
00067 xmms_ipc_msg_t *msg;
00068
00069 msg = x_new0 (xmms_ipc_msg_t, 1);
00070 msg->data = malloc (XMMS_IPC_MSG_DEFAULT_SIZE);
00071 memset (msg->data, 0, XMMS_IPC_MSG_HEAD_LEN);
00072 msg->size = XMMS_IPC_MSG_DEFAULT_SIZE;
00073
00074 return msg;
00075 }
00076
00077 xmms_ipc_msg_t *
00078 xmms_ipc_msg_new (uint32_t object, uint32_t cmd)
00079 {
00080 xmms_ipc_msg_t *msg;
00081
00082 msg = xmms_ipc_msg_alloc ();
00083
00084 xmms_ipc_msg_set_cmd (msg, cmd);
00085 xmms_ipc_msg_set_object (msg, object);
00086
00087 return msg;
00088 }
00089
00090 void
00091 xmms_ipc_msg_destroy (xmms_ipc_msg_t *msg)
00092 {
00093 x_return_if_fail (msg);
00094
00095 free (msg->data);
00096 free (msg);
00097 }
00098
00099 void
00100 xmms_ipc_msg_set_length (xmms_ipc_msg_t *msg, uint32_t len)
00101 {
00102 x_return_if_fail (msg);
00103
00104 msg->data->header.length = htonl (len);
00105 }
00106
00107 uint32_t
00108 xmms_ipc_msg_get_length (const xmms_ipc_msg_t *msg)
00109 {
00110 x_return_val_if_fail (msg, 0);
00111
00112 return ntohl (msg->data->header.length);
00113 }
00114
00115 uint32_t
00116 xmms_ipc_msg_get_object (const xmms_ipc_msg_t *msg)
00117 {
00118 x_return_val_if_fail (msg, 0);
00119
00120 return ntohl (msg->data->header.object);
00121 }
00122
00123 void
00124 xmms_ipc_msg_set_object (xmms_ipc_msg_t *msg, uint32_t object)
00125 {
00126 x_return_if_fail (msg);
00127
00128 msg->data->header.object = htonl (object);
00129 }
00130
00131 uint32_t
00132 xmms_ipc_msg_get_cmd (const xmms_ipc_msg_t *msg)
00133 {
00134 x_return_val_if_fail (msg, 0);
00135
00136 return ntohl (msg->data->header.cmd);
00137 }
00138
00139 void
00140 xmms_ipc_msg_set_cmd (xmms_ipc_msg_t *msg, uint32_t cmd)
00141 {
00142 x_return_if_fail (msg);
00143
00144 msg->data->header.cmd = htonl (cmd);
00145 }
00146
00147 void
00148 xmms_ipc_msg_set_cookie (xmms_ipc_msg_t *msg, uint32_t cookie)
00149 {
00150 msg->data->header.cookie = htonl (cookie);
00151 }
00152
00153 uint32_t
00154 xmms_ipc_msg_get_cookie (const xmms_ipc_msg_t *msg)
00155 {
00156 x_return_val_if_fail (msg, 0);
00157
00158 return ntohl (msg->data->header.cookie);
00159 }
00160
00161
00162
00163
00164
00165
00166
00167
00168
00169 bool
00170 xmms_ipc_msg_write_transport (xmms_ipc_msg_t *msg,
00171 xmms_ipc_transport_t *transport,
00172 bool *disconnected)
00173 {
00174 char *buf;
00175 unsigned int ret, len;
00176
00177 x_return_val_if_fail (msg, false);
00178 x_return_val_if_fail (msg->data, false);
00179 x_return_val_if_fail (transport, false);
00180
00181 len = xmms_ipc_msg_get_length (msg) + XMMS_IPC_MSG_HEAD_LEN;
00182
00183 x_return_val_if_fail (len > msg->xfered, true);
00184
00185 buf = (char *) (msg->data->rawdata + msg->xfered);
00186 ret = xmms_ipc_transport_write (transport, buf, len - msg->xfered);
00187
00188 if (ret == SOCKET_ERROR) {
00189 if (xmms_socket_error_recoverable ()) {
00190 return false;
00191 }
00192
00193 if (disconnected) {
00194 *disconnected = true;
00195 }
00196
00197 return false;
00198 } else if (!ret) {
00199 if (disconnected) {
00200 *disconnected = true;
00201 }
00202 } else {
00203 msg->xfered += ret;
00204 }
00205
00206 return (len == msg->xfered);
00207 }
00208
00209
00210
00211
00212
00213
00214 bool
00215 xmms_ipc_msg_read_transport (xmms_ipc_msg_t *msg,
00216 xmms_ipc_transport_t *transport,
00217 bool *disconnected)
00218 {
00219 char *buf;
00220 unsigned int ret, len;
00221
00222 x_return_val_if_fail (msg, false);
00223 x_return_val_if_fail (transport, false);
00224
00225 while (true) {
00226 len = XMMS_IPC_MSG_HEAD_LEN;
00227
00228 if (msg->xfered >= XMMS_IPC_MSG_HEAD_LEN) {
00229 len += xmms_ipc_msg_get_length (msg);
00230
00231 if (len > msg->size) {
00232 void *newbuf;
00233 newbuf = realloc (msg->data, len);
00234 if (!newbuf) {
00235 if (disconnected) {
00236 *disconnected = true;
00237 }
00238 return false;
00239 }
00240 msg->size = len;
00241 msg->data = newbuf;
00242 }
00243
00244 if (msg->xfered == len) {
00245 return true;
00246 }
00247 }
00248
00249 x_return_val_if_fail (msg->xfered < len, false);
00250
00251 buf = (char *) (msg->data->rawdata + msg->xfered);
00252 ret = xmms_ipc_transport_read (transport, buf, len - msg->xfered);
00253
00254 if (ret == SOCKET_ERROR) {
00255 if (xmms_socket_error_recoverable ()) {
00256 return false;
00257 }
00258
00259 if (disconnected) {
00260 *disconnected = true;
00261 }
00262
00263 return false;
00264 } else if (ret == 0) {
00265 if (disconnected) {
00266 *disconnected = true;
00267 }
00268
00269 return false;
00270 } else {
00271 msg->xfered += ret;
00272 }
00273 }
00274 }
00275
00276 static uint32_t
00277 xmms_ipc_msg_put_data (xmms_ipc_msg_t *msg, const void *data, unsigned int len)
00278 {
00279 uint32_t total;
00280
00281 x_return_val_if_fail (msg, -1);
00282
00283 total = xmms_ipc_msg_get_length (msg) + XMMS_IPC_MSG_HEAD_LEN + len;
00284
00285 if (total > msg->size) {
00286 int realloc_size = XMMS_IPC_MSG_DEFAULT_SIZE;
00287
00288 if (len > XMMS_IPC_MSG_DEFAULT_SIZE) {
00289 realloc_size = len;
00290 }
00291
00292
00293 msg->data = realloc (msg->data, msg->size + realloc_size);
00294 msg->size += realloc_size;
00295 }
00296
00297 total = xmms_ipc_msg_get_length (msg);
00298 memcpy (&msg->data->header.data[total], data, len);
00299 xmms_ipc_msg_set_length (msg, total + len);
00300
00301
00302 return total;
00303 }
00304
00305 uint32_t
00306 xmms_ipc_msg_put_bin (xmms_ipc_msg_t *msg,
00307 const unsigned char *data,
00308 unsigned int len)
00309 {
00310 xmms_ipc_msg_put_uint32 (msg, len);
00311 return xmms_ipc_msg_put_data (msg, data, len);
00312 }
00313
00314 uint32_t
00315 xmms_ipc_msg_put_uint32 (xmms_ipc_msg_t *msg, uint32_t v)
00316 {
00317 v = htonl (v);
00318
00319 return xmms_ipc_msg_put_data (msg, &v, sizeof (v));
00320 }
00321
00322 void
00323 xmms_ipc_msg_store_uint32 (xmms_ipc_msg_t *msg,
00324 uint32_t offset, uint32_t v)
00325 {
00326 v = htonl (v);
00327
00328 memcpy (&msg->data->header.data[offset], &v, sizeof (v));
00329 }
00330
00331 uint32_t
00332 xmms_ipc_msg_put_int32 (xmms_ipc_msg_t *msg, int32_t v)
00333 {
00334 v = htonl (v);
00335
00336 return xmms_ipc_msg_put_data (msg, &v, sizeof (v));
00337 }
00338
00339 uint32_t
00340 xmms_ipc_msg_put_float (xmms_ipc_msg_t *msg, float v)
00341 {
00342
00343 return xmms_ipc_msg_put_data (msg, &v, sizeof (v));
00344 }
00345
00346 uint32_t
00347 xmms_ipc_msg_put_string (xmms_ipc_msg_t *msg, const char *str)
00348 {
00349 if (!msg) {
00350 return -1;
00351 }
00352
00353 if (!str) {
00354 return xmms_ipc_msg_put_uint32 (msg, 0);
00355 }
00356
00357 xmms_ipc_msg_put_uint32 (msg, strlen (str) + 1);
00358
00359 return xmms_ipc_msg_put_data (msg, str, strlen (str) + 1);
00360 }
00361
00362 uint32_t
00363 xmms_ipc_msg_put_string_list (xmms_ipc_msg_t *msg, const char* strings[])
00364 {
00365 uint32_t ret;
00366 int n;
00367
00368 for (n = 0; strings && strings[n] != NULL; n++) { }
00369 ret = xmms_ipc_msg_put_uint32 (msg, n);
00370
00371 for (n = 0; strings && strings[n] != NULL; n++) {
00372 ret = xmms_ipc_msg_put_string (msg, strings[n]);
00373 }
00374
00375 return ret;
00376 }
00377
00378 uint32_t
00379 xmms_ipc_msg_put_collection (xmms_ipc_msg_t *msg, xmmsc_coll_t *coll)
00380 {
00381 int n;
00382 uint32_t ret, *idlist;
00383 xmmsc_coll_t *op;
00384
00385 if (!msg || !coll) {
00386 return -1;
00387 }
00388
00389
00390 xmmsc_coll_operand_list_save (coll);
00391
00392
00393 xmms_ipc_msg_put_uint32 (msg, xmmsc_coll_get_type (coll));
00394
00395
00396 n = 0;
00397 xmmsc_coll_attribute_foreach (coll, xmms_ipc_count_coll_attr, &n);
00398 xmms_ipc_msg_put_uint32 (msg, n);
00399
00400 xmmsc_coll_attribute_foreach (coll, xmms_ipc_append_coll_attr, msg);
00401
00402
00403 idlist = xmmsc_coll_get_idlist (coll);
00404 for (n = 0; idlist[n] != 0; n++) { }
00405
00406 xmms_ipc_msg_put_uint32 (msg, n);
00407 for (n = 0; idlist[n] != 0; n++) {
00408 xmms_ipc_msg_put_uint32 (msg, idlist[n]);
00409 }
00410
00411
00412 n = 0;
00413 if (xmmsc_coll_get_type (coll) != XMMS_COLLECTION_TYPE_REFERENCE) {
00414 xmmsc_coll_operand_list_first (coll);
00415 while (xmmsc_coll_operand_list_entry (coll, &op)) {
00416 n++;
00417 xmmsc_coll_operand_list_next (coll);
00418 }
00419 }
00420
00421 ret = xmms_ipc_msg_put_uint32 (msg, n);
00422
00423 if (n > 0) {
00424 xmmsc_coll_operand_list_first (coll);
00425 while (xmmsc_coll_operand_list_entry (coll, &op)) {
00426 ret = xmms_ipc_msg_put_collection (msg, op);
00427 xmmsc_coll_operand_list_next (coll);
00428 }
00429 }
00430
00431
00432 xmmsc_coll_operand_list_restore (coll);
00433
00434 return ret;
00435 }
00436
00437 static bool
00438 xmms_ipc_msg_get_data (xmms_ipc_msg_t *msg, void *buf, unsigned int len)
00439 {
00440 if (!msg)
00441 return false;
00442
00443 if (len > xmms_ipc_msg_get_length (msg) - msg->get_pos)
00444 return false;
00445
00446 if (buf) {
00447 memcpy (buf, &msg->data->header.data[msg->get_pos], len);
00448 }
00449
00450 msg->get_pos += len;
00451
00452 return true;
00453 }
00454
00455 bool
00456 xmms_ipc_msg_get_uint32 (xmms_ipc_msg_t *msg, uint32_t *v)
00457 {
00458 bool ret;
00459
00460 ret = xmms_ipc_msg_get_data (msg, v, sizeof (*v));
00461
00462 if (v) {
00463 *v = ntohl (*v);
00464 }
00465
00466 return ret;
00467 }
00468
00469 bool
00470 xmms_ipc_msg_get_int32 (xmms_ipc_msg_t *msg, int32_t *v)
00471 {
00472 bool ret;
00473
00474 ret = xmms_ipc_msg_get_data (msg, v, sizeof (*v));
00475
00476 if (v) {
00477 *v = ntohl (*v);
00478 }
00479
00480 return ret;
00481 }
00482
00483 bool
00484 xmms_ipc_msg_get_float (xmms_ipc_msg_t *msg, float *v)
00485 {
00486
00487 return xmms_ipc_msg_get_data (msg, v, sizeof (*v));
00488 }
00489
00490 bool
00491 xmms_ipc_msg_get_string_alloc (xmms_ipc_msg_t *msg, char **buf,
00492 unsigned int *len)
00493 {
00494 char *str;
00495 unsigned int l;
00496
00497 if (!xmms_ipc_msg_get_uint32 (msg, &l)) {
00498 return false;
00499 }
00500
00501 if (l > xmms_ipc_msg_get_length (msg) - msg->get_pos)
00502 return false;
00503
00504 str = x_malloc (l + 1);
00505 if (!str) {
00506 return false;
00507 }
00508
00509 if (!xmms_ipc_msg_get_data (msg, str, l)) {
00510 free (str);
00511 return false;
00512 }
00513
00514 str[l] = '\0';
00515
00516 *buf = str;
00517 *len = l;
00518
00519 return true;
00520 }
00521
00522 bool
00523 xmms_ipc_msg_get_bin_alloc (xmms_ipc_msg_t *msg,
00524 unsigned char **buf,
00525 unsigned int *len)
00526 {
00527 unsigned char *b;
00528 unsigned int l;
00529
00530 if (!xmms_ipc_msg_get_uint32 (msg, &l)) {
00531 return false;
00532 }
00533
00534 if (l > xmms_ipc_msg_get_length (msg) - msg->get_pos)
00535 return false;
00536
00537 b = x_malloc (l);
00538 if (!b) {
00539 return false;
00540 }
00541
00542 if (!xmms_ipc_msg_get_data (msg, b, l)) {
00543 free (b);
00544 return false;
00545 }
00546
00547 *buf = b;
00548 *len = l;
00549
00550 return true;
00551 }
00552
00553 bool
00554 xmms_ipc_msg_get_string (xmms_ipc_msg_t *msg, char *buf, unsigned int maxlen)
00555 {
00556 uint32_t len;
00557
00558 if (buf) {
00559 buf[maxlen - 1] = '\0';
00560 maxlen--;
00561 }
00562
00563 if (!xmms_ipc_msg_get_uint32 (msg, &len)) {
00564 return false;
00565 }
00566
00567 if (!len) {
00568 buf[0] = '\0';
00569 return true;
00570 }
00571
00572 if (!xmms_ipc_msg_get_data (msg, buf, MIN (maxlen, len))) {
00573 return false;
00574 }
00575
00576 if (maxlen < len) {
00577 xmms_ipc_msg_get_data (msg, NULL, len - maxlen);
00578 }
00579
00580 return true;
00581 }
00582
00583 bool
00584 xmms_ipc_msg_get_collection_alloc (xmms_ipc_msg_t *msg, xmmsc_coll_t **coll)
00585 {
00586 unsigned int i;
00587 unsigned int type;
00588 unsigned int n_items;
00589 unsigned int id;
00590 uint32_t *idlist = NULL;
00591 char *key, *val;
00592
00593
00594 if (!xmms_ipc_msg_get_uint32 (msg, &type)) {
00595 return false;
00596 }
00597
00598 *coll = xmmsc_coll_new (type);
00599
00600
00601 if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
00602 goto err;
00603 }
00604
00605 for (i = 0; i < n_items; i++) {
00606 unsigned int len;
00607 if (!xmms_ipc_msg_get_string_alloc (msg, &key, &len)) {
00608 goto err;
00609 }
00610 if (!xmms_ipc_msg_get_string_alloc (msg, &val, &len)) {
00611 free (key);
00612 goto err;
00613 }
00614
00615 xmmsc_coll_attribute_set (*coll, key, val);
00616 free (key);
00617 free (val);
00618 }
00619
00620
00621 if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
00622 goto err;
00623 }
00624
00625 if (!(idlist = x_new (uint32_t, n_items + 1))) {
00626 goto err;
00627 }
00628
00629 for (i = 0; i < n_items; i++) {
00630 if (!xmms_ipc_msg_get_uint32 (msg, &id)) {
00631 goto err;
00632 }
00633
00634 idlist[i] = id;
00635 }
00636
00637 idlist[i] = 0;
00638 xmmsc_coll_set_idlist (*coll, idlist);
00639 free (idlist);
00640 idlist = NULL;
00641
00642
00643 if (!xmms_ipc_msg_get_uint32 (msg, &n_items)) {
00644 goto err;
00645 }
00646
00647 for (i = 0; i < n_items; i++) {
00648 xmmsc_coll_t *operand;
00649
00650 if (!xmms_ipc_msg_get_collection_alloc (msg, &operand)) {
00651 goto err;
00652 }
00653
00654 xmmsc_coll_add_operand (*coll, operand);
00655 xmmsc_coll_unref (operand);
00656 }
00657
00658 return true;
00659
00660 err:
00661 if (idlist != NULL) {
00662 free (idlist);
00663 }
00664
00665 xmmsc_coll_unref (*coll);
00666
00667 return false;
00668 }