00001
00002
00003
00004
00005
00006
00007
00008
00009
00010
00011
00012
00013
00014
00015
00016
00017
00018
00019 #include "lsm_ipc.hpp"
00020
00021 #include "libstoragemgmt/libstoragemgmt_plug_interface.h"
00022
00023 #include <unistd.h>
00024 #include <errno.h>
00025 #include <sys/un.h>
00026 #include <sys/socket.h>
00027 #include <string.h>
00028 #include <iomanip>
00029 #include <sstream>
00030 #include <iostream>
00031 #include <algorithm>
00032 #include <stdio.h>
00033 #include <list>
00034
00035 #ifdef HAVE_CONFIG_H
00036 #include "config.h"
00037 #endif
00038
00039 #ifdef HAVE_YAJL_YAJL_VERSION_H
00040 #include <yajl/yajl_version.h>
00041 #endif
00042
00043
00044 #if defined(HAVE_YAJL_YAJL_VERSION_H) && YAJL_MAJOR > 1
00045 #define LSM_NEW_YAJL
00046 #endif
00047
00048 static std::string zero_pad_num(unsigned int num)
00049 {
00050 std::ostringstream ss;
00051 ss << std::setw(Transport::HDR_LEN) << std::setfill('0') << num;
00052 return ss.str();
00053 }
00054
00055 Transport::Transport():s(-1)
00056 {
00057 }
00058
00059 Transport::Transport(int socket_desc):s(socket_desc)
00060 {
00061 }
00062
00063 int Transport::msg_send(const std::string & msg, int &error_code)
00064 {
00065 int rc = -1;
00066 error_code = 0;
00067
00068 if (msg.size() > 0) {
00069 ssize_t written = 0;
00070
00071 std::string data = zero_pad_num(msg.size()) + msg;
00072 ssize_t msg_size = data.size();
00073
00074 while (written < msg_size) {
00075 int wrote = send(s, data.c_str() + written, (msg_size - written),
00076 MSG_NOSIGNAL);
00077 if (wrote != -1) {
00078 written += wrote;
00079 } else {
00080 error_code = errno;
00081 break;
00082 }
00083 }
00084
00085 if ((written == msg_size) && error_code == 0) {
00086 rc = 0;
00087 }
00088 }
00089 return rc;
00090 }
00091
00092 static std::string string_read(int fd, size_t count, int &error_code)
00093 {
00094 char buff[4096];
00095 size_t amount_read = 0;
00096 std::string rc = "";
00097
00098 error_code = 0;
00099
00100 while (amount_read < count) {
00101 ssize_t rd = recv(fd, buff, std::min(sizeof(buff),
00102 (count - amount_read)),
00103 MSG_WAITALL);
00104 if (rd > 0) {
00105 amount_read += rd;
00106 rc += std::string(buff, rd);
00107 } else {
00108 error_code = errno;
00109 break;
00110 }
00111 }
00112
00113 if ((amount_read == count) && (error_code == 0))
00114 return rc;
00115 else
00116 throw EOFException("");
00117 }
00118
00119 std::string Transport::msg_recv(int &error_code)
00120 {
00121 std::string msg;
00122 error_code = 0;
00123 unsigned long int payload_len = 0;
00124 std::string len = string_read(s, HDR_LEN, error_code);
00125 if (len.size() && error_code == 0) {
00126 payload_len = strtoul(len.c_str(), NULL, 10);
00127 if (payload_len < 0x80000000) {
00128 msg = string_read(s, payload_len, error_code);
00129 }
00130
00131 }
00132 return msg;
00133 }
00134
00135 int Transport::socket_get(const std::string & path, int &error_code)
00136 {
00137 int sfd = socket(AF_UNIX, SOCK_STREAM, 0);
00138 int rc = -1;
00139 error_code = 0;
00140
00141 if (sfd != -1) {
00142 struct sockaddr_un addr;
00143
00144 memset(&addr, 0, sizeof(addr));
00145 addr.sun_family = AF_UNIX;
00146 strncpy(addr.sun_path, path.c_str(), sizeof(addr.sun_path) - 1);
00147
00148
00149 rc = connect(sfd, (struct sockaddr *) &addr, sizeof(addr));
00150 if (rc != 0) {
00151 error_code = errno;
00152 rc = -1;
00153 ::close(sfd);
00154 } else {
00155 rc = sfd;
00156 }
00157 }
00158 return rc;
00159 }
00160
00161 Transport::~Transport()
00162 {
00163 close();
00164 }
00165
00166 int Transport::close()
00167 {
00168 int rc = EBADF;
00169
00170 if (s >= 0) {
00171 int rc =::close(s);
00172 if (rc != 0) {
00173 rc = errno;
00174 }
00175
00176 s = -1;
00177 }
00178 return rc;
00179 }
00180
00181 EOFException::EOFException(std::string m):std::runtime_error(m)
00182 {
00183 }
00184
00185 ValueException::ValueException(std::string m):std::runtime_error(m)
00186 {
00187 }
00188
00189 LsmException::LsmException(int code, std::string & msg):
00190 std::runtime_error(msg), error_code(code)
00191 {
00192
00193 }
00194
00195 LsmException::LsmException(int code, std::string & msg,
00196 const std::
00197 string & debug_addl):std::runtime_error(msg),
00198 error_code(code), debug(debug_addl)
00199 {
00200 }
00201
00202 LsmException::~LsmException()throw()
00203 {
00204 }
00205
00206 LsmException::LsmException(int code, std::string & msg,
00207 const std::string & debug_addl,
00208 const std::
00209 string & debug_data_addl):std::runtime_error(msg),
00210 error_code(code), debug(debug_addl), debug_data(debug_data_addl)
00211 {
00212 }
00213
00214 Value::Value(void):t(null_t)
00215 {
00216 }
00217
00218 Value::Value(bool v):t(boolean_t), s((v) ? "true" : "false")
00219 {
00220 }
00221
00222 Value::Value(double v):t(numeric_t), s(to_string(v))
00223 {
00224 }
00225
00226 Value::Value(long double v):t(numeric_t), s(to_string(v))
00227 {
00228 }
00229
00230 Value::Value(uint32_t v):t(numeric_t), s(to_string(v))
00231 {
00232 }
00233
00234 Value::Value(int32_t v):t(numeric_t), s(to_string(v))
00235 {
00236 }
00237
00238 Value::Value(uint64_t v):t(numeric_t), s(to_string(v))
00239 {
00240 }
00241
00242 Value::Value(int64_t v):t(numeric_t), s(to_string(v))
00243 {
00244 }
00245
00246 Value::Value(value_type type, const std::string & v):t(type), s(v)
00247 {
00248 }
00249
00250 Value::Value(const std::vector < Value > &v):t(array_t), array(v)
00251 {
00252 }
00253
00254 Value::Value(const char *v)
00255 {
00256 if (v) {
00257 t = string_t;
00258 s = std::string(v);
00259 } else {
00260 t = null_t;
00261 }
00262 }
00263
00264 Value::Value(const std::string & v):t(string_t), s(v)
00265 {
00266 }
00267
00268 Value::Value(const std::map < std::string, Value > &v):t(object_t), obj(v)
00269 {
00270 }
00271
00272 std::string Value::serialize(void)
00273 {
00274 const unsigned char *buf;
00275 std::string json;
00276
00277 #ifdef LSM_NEW_YAJL
00278 size_t len;
00279 yajl_gen g = yajl_gen_alloc(NULL);
00280 if (g) {
00281
00282 yajl_gen_config(g, yajl_gen_beautify, 1);
00283 yajl_gen_config(g, yajl_gen_indent_string, " ");
00284 }
00285 #else
00286 unsigned int len;
00287 yajl_gen_config conf = { 1, " " };
00288 yajl_gen g = yajl_gen_alloc(&conf, NULL);
00289 #endif
00290
00291 if (g) {
00292 marshal(g);
00293
00294 if (yajl_gen_status_ok == yajl_gen_get_buf(g, &buf, &len)) {
00295 json = std::string((const char *) buf);
00296 }
00297 yajl_gen_free(g);
00298 }
00299 return json;
00300 }
00301
00302 Value::value_type Value::valueType() const
00303 {
00304 return t;
00305 }
00306
00307 Value & Value::operator[](const std::string & key) {
00308 if (t == object_t) {
00309 return obj[key];
00310 }
00311 throw ValueException("Value not object");
00312 }
00313
00314 Value & Value::operator[](uint32_t i) {
00315 if (t == array_t) {
00316 return array[i];
00317 }
00318 throw ValueException("Value not array");
00319 }
00320
00321 bool Value::hasKey(const std::string & k)
00322 {
00323 if (t == object_t) {
00324 std::map < std::string, Value >::iterator iter = obj.find(k);
00325 if (iter != obj.end() && iter->first == k) {
00326 return true;
00327 }
00328 }
00329 return false;
00330 }
00331
00332 bool Value::isValidRequest()
00333 {
00334 return (t == Value::object_t && hasKey("method") &&
00335 hasKey("id") && hasKey("params"));
00336 }
00337
00338 Value Value::getValue(const char *key)
00339 {
00340 if (hasKey(key)) {
00341 return obj[key];
00342 }
00343 return Value();
00344 }
00345
00346 const char *Value::asNumString()
00347 {
00348 const char *rc = NULL;
00349
00350 if (t == numeric_t) {
00351 rc = s.c_str();
00352 }
00353 return rc;
00354 }
00355
00356 void *Value::asVoid()
00357 {
00358 if (t == null_t) {
00359 return NULL;
00360 }
00361 throw ValueException("Value not null");
00362 }
00363
00364 bool Value::asBool()
00365 {
00366 if (t == boolean_t) {
00367 return (s == "true");
00368 }
00369 throw ValueException("Value not boolean");
00370 }
00371
00372 double Value::asDouble()
00373 {
00374 if (t == numeric_t) {
00375 double rc;
00376
00377 if (sscanf(s.c_str(), "%lf", &rc) > 0) {
00378 return rc;
00379 }
00380 throw ValueException("Value not a double");
00381 }
00382 throw ValueException("Value not numeric");
00383 }
00384
00385 long double Value::asLongDouble()
00386 {
00387 if (t == numeric_t) {
00388 long double rc;
00389
00390 if (sscanf(s.c_str(), "%Lf", &rc) > 0) {
00391 return rc;
00392 }
00393 throw ValueException("Value not a long double");
00394 }
00395 throw ValueException("Value not numeric");
00396 }
00397
00398 int32_t Value::asInt32_t()
00399 {
00400 if (t == numeric_t) {
00401 int32_t rc;
00402
00403 if (sscanf(s.c_str(), "%d", &rc) > 0) {
00404 return rc;
00405 }
00406 throw ValueException("Value not int32");
00407 }
00408 throw ValueException("Value not numeric");
00409 }
00410
00411 int64_t Value::asInt64_t()
00412 {
00413 if (t == numeric_t) {
00414 int64_t rc;
00415 if (sscanf(s.c_str(), "%lld", (long long int *) &rc) > 0) {
00416 return rc;
00417 }
00418 throw ValueException("Not an integer");
00419 }
00420 throw ValueException("Value not numeric");
00421 }
00422
00423 uint32_t Value::asUint32_t()
00424 {
00425 if (t == numeric_t) {
00426 uint32_t rc;
00427 if (sscanf(s.c_str(), "%u", &rc) > 0) {
00428 return rc;
00429 }
00430 throw ValueException("Not an integer");
00431 }
00432 throw ValueException("Value not numeric");
00433 }
00434
00435 uint64_t Value::asUint64_t()
00436 {
00437 if (t == numeric_t) {
00438 uint64_t rc;
00439 if (sscanf(s.c_str(), "%llu", (long long unsigned int *) &rc) > 0) {
00440 return rc;
00441 }
00442 throw ValueException("Not an integer");
00443 }
00444 throw ValueException("Value not numeric");
00445 }
00446
00447 std::string Value::asString()
00448 {
00449 if (t == string_t) {
00450 return s;
00451 } else if (t == null_t) {
00452 return std::string();
00453 }
00454 throw ValueException("Value not string");
00455 }
00456
00457 const char *Value::asC_str()
00458 {
00459 if (t == string_t) {
00460 return s.c_str();
00461 } else if (t == null_t) {
00462 return NULL;
00463 }
00464 throw ValueException("Value not string");
00465 }
00466
00467 std::map < std::string, Value > Value::asObject()
00468 {
00469 if (t == object_t) {
00470 return obj;
00471 }
00472 throw ValueException("Value not object");
00473 }
00474
00475 std::vector < Value > Value::asArray()
00476 {
00477 if (t == array_t) {
00478 return array;
00479 }
00480 throw ValueException("Value not array");
00481 }
00482
00483 void Value::marshal(yajl_gen g)
00484 {
00485 switch (t) {
00486 case (null_t):
00487 {
00488 if (yajl_gen_status_ok != yajl_gen_null(g)) {
00489 throw ValueException("yajl_gen_null failure");
00490 }
00491 break;
00492 }
00493 case (boolean_t):
00494 {
00495 if (yajl_gen_status_ok != yajl_gen_bool(g, (s == "true") ? 1 : 0)) {
00496 throw ValueException("yajl_gen_bool failure");
00497 }
00498 break;
00499 }
00500 case (string_t):
00501 {
00502 if (yajl_gen_status_ok !=
00503 yajl_gen_string(g, (const unsigned char *) s.c_str(),
00504 s.size())) {
00505 throw ValueException("yajl_gen_string failure");
00506 }
00507 break;
00508 }
00509 case (numeric_t):
00510 {
00511 if (yajl_gen_status_ok != yajl_gen_number(g, s.c_str(), s.size())) {
00512 throw ValueException("yajl_gen_number failure");
00513 }
00514 break;
00515 }
00516 case (object_t):
00517 {
00518
00519 if (yajl_gen_status_ok != yajl_gen_map_open(g)) {
00520 throw ValueException("yajl_gen_map_open failure");
00521 }
00522
00523 std::map < std::string, Value >::iterator iter;
00524
00525 for (iter = obj.begin(); iter != obj.end(); iter++) {
00526 if (yajl_gen_status_ok != yajl_gen_string(g,
00527 (const unsigned
00528 char *) iter->first.
00529 c_str(),
00530 iter->first.size())) {
00531 throw ValueException("yajl_gen_string failure");
00532 }
00533 iter->second.marshal(g);
00534 }
00535
00536 if (yajl_gen_status_ok != yajl_gen_map_close(g)) {
00537 throw ValueException("yajl_gen_map_close failure");
00538 }
00539 break;
00540 }
00541 case (array_t):
00542 {
00543 if (yajl_gen_status_ok != yajl_gen_array_open(g)) {
00544 throw ValueException("yajl_gen_array_open failure");
00545 }
00546
00547 for (unsigned int i = 0; i < array.size(); ++i) {
00548 array[i].marshal(g);
00549 }
00550
00551 if (yajl_gen_status_ok != yajl_gen_array_close(g)) {
00552 throw ValueException("yajl_gen_array_close failure");
00553 }
00554 break;
00555 }
00556 }
00557 }
00558
00559 class LSM_DLL_LOCAL ParseElement {
00560 public:
00561
00562 enum parse_type {
00563 null, boolean, string, number, begin_map, end_map,
00564 begin_array, end_array, map_key, unknown
00565 };
00566
00567 ParseElement():t(unknown) {
00568 } ParseElement(parse_type type):t(type) {
00569 }
00570
00571 ParseElement(parse_type type, std::string value):t(type), v(value) {
00572 }
00573 parse_type t;
00574 std::string v;
00575
00576 std::string to_string() {
00577 return "type " +::to_string(t) + ": value" + v;
00578 }
00579 };
00580
00581 #ifdef LSM_NEW_YAJL
00582 #define YAJL_SIZE_T size_t
00583 #else
00584 #define YAJL_SIZE_T unsigned int
00585 #endif
00586
00587 static int handle_value(void *ctx, ParseElement::parse_type type)
00588 {
00589 std::list < ParseElement > *l = (std::list < ParseElement > *)ctx;
00590 l->push_back(ParseElement(type));
00591 return 1;
00592 }
00593
00594 static int handle_value(void *ctx, ParseElement::parse_type type,
00595 const char *s, size_t len)
00596 {
00597 std::list < ParseElement > *l = (std::list < ParseElement > *)ctx;
00598 l->push_back(ParseElement(type, std::string(s, len)));
00599 return 1;
00600 }
00601
00602 static int handle_null(void *ctx)
00603 {
00604 return handle_value(ctx, ParseElement::null);
00605 }
00606
00607 static int handle_boolean(void *ctx, int boolean)
00608 {
00609 std::string b = (boolean) ? "true" : "false";
00610 return handle_value(ctx, ParseElement::boolean, b.c_str(), b.size());
00611 }
00612
00613 static int handle_number(void *ctx, const char *s, YAJL_SIZE_T len)
00614 {
00615 return handle_value(ctx, ParseElement::number, s, len);
00616 }
00617
00618 static int handle_string(void *ctx, const unsigned char *stringVal,
00619 YAJL_SIZE_T len)
00620 {
00621 return handle_value(ctx, ParseElement::string,
00622 (const char *) stringVal, len);
00623 }
00624
00625 static int handle_map_key(void *ctx, const unsigned char *stringVal,
00626 YAJL_SIZE_T len)
00627 {
00628 return handle_value(ctx, ParseElement::map_key,
00629 (const char *) stringVal, len);
00630 }
00631
00632 static int handle_start_map(void *ctx)
00633 {
00634 return handle_value(ctx, ParseElement::begin_map);
00635 }
00636
00637 static int handle_end_map(void *ctx)
00638 {
00639 return handle_value(ctx, ParseElement::end_map);
00640 }
00641
00642 static int handle_start_array(void *ctx)
00643 {
00644 return handle_value(ctx, ParseElement::begin_array);
00645 }
00646
00647 static int handle_end_array(void *ctx)
00648 {
00649 return handle_value(ctx, ParseElement::end_array);
00650 }
00651
00652 static yajl_callbacks callbacks = {
00653 handle_null,
00654 handle_boolean,
00655 NULL,
00656 NULL,
00657 handle_number,
00658 handle_string,
00659 handle_start_map,
00660 handle_map_key,
00661 handle_end_map,
00662 handle_start_array,
00663 handle_end_array
00664 };
00665
00666 static ParseElement get_next(std::list < ParseElement > &l)
00667 {
00668 ParseElement rc = l.front();
00669 l.pop_front();
00670 return rc;
00671 }
00672
00673 static Value ParseElements(std::list < ParseElement > &l);
00674
00675 static Value HandleArray(std::list < ParseElement > &l)
00676 {
00677 std::vector < Value > values;
00678
00679 ParseElement cur;
00680
00681 if (!l.empty()) {
00682 do {
00683 cur = l.front();
00684
00685 if (cur.t != ParseElement::end_array) {
00686 values.push_back(ParseElements(l));
00687 } else {
00688 get_next(l);
00689 }
00690
00691 } while (!l.empty() && cur.t != ParseElement::end_array);
00692 }
00693
00694 return Value(values);
00695 }
00696
00697 static Value HandleObject(std::list < ParseElement > &l)
00698 {
00699 std::map < std::string, Value > values;
00700 ParseElement cur;
00701
00702 if (!l.empty()) {
00703 do {
00704 cur = get_next(l);
00705
00706 if (cur.t == ParseElement::map_key) {
00707 values[cur.v] = ParseElements(l);
00708 } else if (cur.t != ParseElement::end_map) {
00709 throw ValueException("Unexpected state: " + cur.to_string());
00710 }
00711 } while (!l.empty() && cur.t != ParseElement::end_map);
00712 }
00713 return Value(values);
00714 }
00715
00716 static Value ParseElements(std::list < ParseElement > &l)
00717 {
00718 if (!l.empty()) {
00719 ParseElement cur = get_next(l);
00720
00721 switch (cur.t) {
00722 case (ParseElement::null):
00723 case (ParseElement::boolean):
00724 case (ParseElement::string):
00725 case (ParseElement::number):
00726 {
00727 return Value((Value::value_type) cur.t, cur.v);
00728 break;
00729 }
00730 case (ParseElement::begin_map):
00731 {
00732 return HandleObject(l);
00733 break;
00734 }
00735 case (ParseElement::end_map):
00736 {
00737 throw ValueException("Unexpected end_map");
00738 break;
00739 }
00740 case (ParseElement::begin_array):
00741 {
00742 return HandleArray(l);
00743 break;
00744 }
00745 case (ParseElement::end_array):
00746 {
00747 throw ValueException("Unexpected end_array");
00748 break;
00749 }
00750 case (ParseElement::map_key):
00751 {
00752 throw ValueException("Unexpected map_key");
00753 break;
00754 }
00755 case (ParseElement::unknown):
00756 {
00757 throw ValueException("Unexpected unknown");
00758 break;
00759 }
00760 }
00761 }
00762 return Value();
00763 }
00764
00765 std::string Payload::serialize(Value & v)
00766 {
00767 return v.serialize();
00768 }
00769
00770 Value Payload::deserialize(const std::string & json)
00771 {
00772 yajl_handle hand;
00773 yajl_status stat;
00774 std::list < ParseElement > l;
00775
00776 #ifdef LSM_NEW_YAJL
00777 hand = yajl_alloc(&callbacks, NULL, (void *) &l);
00778 yajl_config(hand, yajl_allow_comments, 1);
00779 #else
00780 yajl_parser_config cfg = { 1, 1 };
00781 hand = yajl_alloc(&callbacks, &cfg, NULL, (void *) &l);
00782 #endif
00783
00784 if (hand) {
00785 stat =
00786 yajl_parse(hand, (const unsigned char *) json.c_str(), json.size());
00787 yajl_free(hand);
00788
00789 if (stat == yajl_status_ok) {
00790 return ParseElements(l);
00791 } else {
00792 throw ValueException("In-valid json");
00793 }
00794 }
00795 return Value();
00796 }
00797
00798 Ipc::Ipc()
00799 {
00800 }
00801
00802 Ipc::Ipc(int fd):t(fd)
00803 {
00804 }
00805
00806 Ipc::Ipc(std::string socket_path)
00807 {
00808 int e = 0;
00809 int fd = Transport::socket_get(socket_path, e);
00810 if (fd >= 0) {
00811 t = Transport(fd);
00812 }
00813 }
00814
00815 Ipc::~Ipc()
00816 {
00817 t.close();
00818 }
00819
00820 void Ipc::requestSend(const std::string request, const Value & params,
00821 int32_t id)
00822 {
00823 int rc = 0;
00824 int ec = 0;
00825 std::map < std::string, Value > v;
00826
00827 v["method"] = Value(request);
00828 v["id"] = Value(id);
00829 v["params"] = params;
00830
00831 Value req(v);
00832 rc = t.msg_send(Payload::serialize(req), ec);
00833
00834 if (rc != 0) {
00835 std::string em = std::string("Error sending message: errno ")
00836 +::to_string(ec);
00837 throw LsmException((int) LSM_ERR_TRANSPORT_COMMUNICATION, em);
00838 }
00839 }
00840
00841 void Ipc::errorSend(int error_code, std::string msg, std::string debug,
00842 uint32_t id)
00843 {
00844 int ec = 0;
00845 int rc = 0;
00846 std::map < std::string, Value > v;
00847 std::map < std::string, Value > error_data;
00848
00849 error_data["code"] = Value(error_code);
00850 error_data["message"] = Value(msg);
00851 error_data["data"] = Value(debug);
00852
00853 v["error"] = Value(error_data);
00854 v["id"] = Value(id);
00855
00856 Value e(v);
00857 rc = t.msg_send(Payload::serialize(e), ec);
00858
00859 if (rc != 0) {
00860 std::string em = std::string("Error sending error message: errno ")
00861 +::to_string(ec);
00862 throw LsmException((int) LSM_ERR_TRANSPORT_COMMUNICATION, em);
00863 }
00864 }
00865
00866 Value Ipc::readRequest(void)
00867 {
00868 int ec;
00869 std::string resp = t.msg_recv(ec);
00870 return Payload::deserialize(resp);
00871 }
00872
00873 void Ipc::responseSend(const Value & response, uint32_t id)
00874 {
00875 int rc;
00876 int ec;
00877 std::map < std::string, Value > v;
00878
00879 v["id"] = id;
00880 v["result"] = response;
00881
00882 Value resp(v);
00883 rc = t.msg_send(Payload::serialize(resp), ec);
00884
00885 if (rc != 0) {
00886 std::string em = std::string("Error sending response: errno ")
00887 +::to_string(ec);
00888 throw LsmException((int) LSM_ERR_TRANSPORT_COMMUNICATION, em);
00889 }
00890 }
00891
00892 Value Ipc::responseRead()
00893 {
00894 Value r = readRequest();
00895 if (r.hasKey(std::string("result"))) {
00896 return r.getValue("result");
00897 } else {
00898 std::map < std::string, Value > rp = r.asObject();
00899 std::map < std::string, Value > error = rp["error"].asObject();
00900
00901 std::string msg = error["message"].asString();
00902 std::string data = error["data"].asString();
00903 throw LsmException((int) (error["code"].asInt32_t()), msg, data);
00904 }
00905 }
00906
00907 Value Ipc::rpc(const std::string & request, const Value & params, int32_t id)
00908 {
00909 requestSend(request, params, id);
00910 return responseRead();
00911 }