static int send_response(GAState *s, QObject *payload) { const char *buf; QString *payload_qstr, *response_qstr; GIOStatus status; g_assert(payload && s->channel); payload_qstr = qobject_to_json(payload); if (!payload_qstr) { return -EINVAL; } if (s->delimit_response) { s->delimit_response = false; response_qstr = qstring_new(); qstring_append_chr(response_qstr, QGA_SENTINEL_BYTE); qstring_append(response_qstr, qstring_get_str(payload_qstr)); QDECREF(payload_qstr); } else { response_qstr = payload_qstr; } qstring_append_chr(response_qstr, '\n'); buf = qstring_get_str(response_qstr); status = ga_channel_write_all(s->channel, buf, strlen(buf)); QDECREF(response_qstr); if (status != G_IO_STATUS_NORMAL) { return -EIO; } return 0; }
/* test commands that involve both input parameters and return values */ static void test_dispatch_cmd_io(void) { QDict *req = qdict_new(); QDict *args = qdict_new(); QDict *ud1a = qdict_new(); QDict *ud1b = qdict_new(); QObject *resp; qdict_put_obj(ud1a, "integer", QOBJECT(qint_from_int(42))); qdict_put_obj(ud1a, "string", QOBJECT(qstring_from_str("hello"))); qdict_put_obj(ud1b, "integer", QOBJECT(qint_from_int(422))); qdict_put_obj(ud1b, "string", QOBJECT(qstring_from_str("hello2"))); qdict_put_obj(args, "ud1a", QOBJECT(ud1a)); qdict_put_obj(args, "ud1b", QOBJECT(ud1b)); qdict_put_obj(req, "arguments", QOBJECT(args)); qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2"))); /* TODO: put in full payload and check for errors */ resp = qmp_dispatch(QOBJECT(req)); assert(resp != NULL); assert(!qdict_haskey(qobject_to_qdict(resp), "error")); g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp))); qobject_decref(resp); QDECREF(req); }
static int conn_channel_send_payload(GIOChannel *channel, QObject *payload) { int ret = 0; const char *buf; QString *payload_qstr; GError *err = NULL; g_assert(payload && channel); payload_qstr = qobject_to_json(payload); if (!payload_qstr) { return -EINVAL; } qstring_append_chr(payload_qstr, '\n'); buf = qstring_get_str(payload_qstr); ret = conn_channel_send_buf(channel, buf, strlen(buf)); if (ret) { goto out_free; } g_io_channel_flush(channel, &err); if (err != NULL) { g_warning("error flushing payload: %s", err->message); ret = err->code; goto out_free; } out_free: QDECREF(payload_qstr); if (err) { g_error_free(err); } return ret; }
/** * qerror_print(): Print QError data * * This function will print the member 'desc' of the specified QError object, * it uses error_report() for this, so that the output is routed to the right * place (ie. stderr or Monitor's device). */ void qerror_print(QError *qerror) { QString *qstring = qerror_human(qerror); loc_push_restore(&qerror->loc); error_report("%s", qstring_get_str(qstring)); loc_pop(&qerror->loc); QDECREF(qstring); }
static void add_pc_test_cases(void) { QDict *response, *minfo; QList *list; const QListEntry *p; QObject *qobj; QString *qstr; const char *mname, *path; PCTestData *data; qtest_start("-machine none"); response = qmp("{ 'execute': 'query-machines' }"); g_assert(response); list = qdict_get_qlist(response, "return"); g_assert(list); for (p = qlist_first(list); p; p = qlist_next(p)) { minfo = qobject_to_qdict(qlist_entry_obj(p)); g_assert(minfo); qobj = qdict_get(minfo, "name"); g_assert(qobj); qstr = qobject_to_qstring(qobj); g_assert(qstr); mname = qstring_get_str(qstr); if (!g_str_has_prefix(mname, "pc-")) { continue; } data = g_malloc(sizeof(PCTestData)); data->machine = mname; data->cpu_model = "Haswell"; /* 1.3+ theoretically */ data->sockets = 1; data->cores = 3; data->threads = 2; data->maxcpus = data->sockets * data->cores * data->threads * 2; if (g_str_has_suffix(mname, "-1.4") || (strcmp(mname, "pc-1.3") == 0) || (strcmp(mname, "pc-1.2") == 0) || (strcmp(mname, "pc-1.1") == 0) || (strcmp(mname, "pc-1.0") == 0) || (strcmp(mname, "pc-0.15") == 0) || (strcmp(mname, "pc-0.14") == 0) || (strcmp(mname, "pc-0.13") == 0) || (strcmp(mname, "pc-0.12") == 0) || (strcmp(mname, "pc-0.11") == 0) || (strcmp(mname, "pc-0.10") == 0)) { path = g_strdup_printf("cpu/%s/init/%ux%ux%u&maxcpus=%u", mname, data->sockets, data->cores, data->threads, data->maxcpus); qtest_add_data_func(path, data, test_pc_without_cpu_add); } else { path = g_strdup_printf("cpu/%s/add/%ux%ux%u&maxcpus=%u", mname, data->sockets, data->cores, data->threads, data->maxcpus); qtest_add_data_func(path, data, test_pc_with_cpu_add); } } qtest_end(); }
/* Only compares bool, int, string */ static void qdict_cmp_do_simple(const char *key, QObject *obj1, void *opaque) { QObject *obj2; QDictCmpData d_new, *d = opaque; if (!d->result) { return; } obj2 = qdict_get(d->expect, key); if (!obj2) { d->result = false; return; } if (qobject_type(obj1) != qobject_type(obj2)) { d->result = false; return; } switch (qobject_type(obj1)) { case QTYPE_QBOOL: d->result = (qbool_get_bool(qobject_to_qbool(obj1)) == qbool_get_bool(qobject_to_qbool(obj2))); return; case QTYPE_QINT: d->result = (qint_get_int(qobject_to_qint(obj1)) == qint_get_int(qobject_to_qint(obj2))); return; case QTYPE_QSTRING: d->result = g_strcmp0(qstring_get_str(qobject_to_qstring(obj1)), qstring_get_str(qobject_to_qstring(obj2))) == 0; return; case QTYPE_QDICT: d_new.expect = qobject_to_qdict(obj2); d_new.result = true; qdict_iter(qobject_to_qdict(obj1), qdict_cmp_do_simple, &d_new); d->result = d_new.result; return; default: abort(); } }
const char *qdict_get_try_str(const QDict *qdict, const char *key) { QObject *obj; obj = qdict_get(qdict, key); if (!obj || qobject_type(obj) != QTYPE_QSTRING) return NULL; return qstring_get_str(qobject_to_qstring(obj)); }
const char *error_get_pretty(Error *err) { if (err->msg == NULL) { QString *str; str = qerror_format(err->fmt, err->obj); err->msg = g_strdup(qstring_get_str(str)); QDECREF(str); } return err->msg; }
static int qemu_rbd_set_keypairs(rados_t cluster, const char *keypairs_json, Error **errp) { QList *keypairs; QString *name; QString *value; const char *key; size_t remaining; int ret = 0; if (!keypairs_json) { return ret; } keypairs = qobject_to(QList, qobject_from_json(keypairs_json, &error_abort)); remaining = qlist_size(keypairs) / 2; assert(remaining); while (remaining--) { name = qobject_to(QString, qlist_pop(keypairs)); value = qobject_to(QString, qlist_pop(keypairs)); assert(name && value); key = qstring_get_str(name); ret = rados_conf_set(cluster, key, qstring_get_str(value)); qobject_unref(value); if (ret < 0) { error_setg_errno(errp, -ret, "invalid conf option %s", key); qobject_unref(name); ret = -EINVAL; break; } qobject_unref(name); } qobject_unref(keypairs); return ret; }
/* test enum values nested in schema-defined structs */ static void test_nested_enums(void) { QmpOutputVisitor *mo; QmpInputVisitor *mi; Visitor *v; NestedEnumsOne *nested_enums, *nested_enums_cpy = NULL; Error *err = NULL; QObject *obj; QString *str; nested_enums = g_malloc0(sizeof(NestedEnumsOne)); nested_enums->enum1 = ENUM_ONE_VALUE1; nested_enums->enum2 = ENUM_ONE_VALUE2; nested_enums->enum3 = ENUM_ONE_VALUE3; nested_enums->enum4 = ENUM_ONE_VALUE3; nested_enums->has_enum2 = false; nested_enums->has_enum4 = true; /* C type -> QObject */ mo = qmp_output_visitor_new(); v = qmp_output_get_visitor(mo); visit_type_NestedEnumsOne(v, &nested_enums, NULL, &err); if (err) { g_error("%s", error_get_pretty(err)); } obj = qmp_output_get_qobject(mo); g_assert(obj); str = qobject_to_json_pretty(obj); g_print("%s\n", qstring_get_str(str)); QDECREF(str); /* QObject -> C type */ mi = qmp_input_visitor_new(obj); v = qmp_input_get_visitor(mi); visit_type_NestedEnumsOne(v, &nested_enums_cpy, NULL, &err); if (err) { g_error("%s", error_get_pretty(err)); } g_assert(nested_enums_cpy); g_assert(nested_enums_cpy->enum1 == nested_enums->enum1); g_assert(nested_enums_cpy->enum3 == nested_enums->enum3); g_assert(nested_enums_cpy->enum4 == nested_enums->enum4); g_assert(nested_enums_cpy->has_enum2 == false); g_assert(nested_enums_cpy->has_enum4 == true); qmp_output_visitor_cleanup(mo); qmp_input_visitor_cleanup(mi); qapi_free_NestedEnumsOne(nested_enums); qapi_free_NestedEnumsOne(nested_enums_cpy); }
static char *to_json_str(QString *str) { QString *json = qobject_to_json(QOBJECT(str)); char *jstr; if (!json) { return NULL; } /* peel off double quotes */ jstr = g_strndup(qstring_get_str(json) + 1, qstring_get_length(json) - 2); qobject_unref(json); return jstr; }
static void qmp_input_type_str(Visitor *v, char **obj, const char *name, Error **errp) { QmpInputVisitor *qiv = to_qiv(v); QObject *qobj = qmp_input_get_object(qiv, name, true); if (!qobj || qobject_type(qobj) != QTYPE_QSTRING) { error_set(errp, QERR_INVALID_PARAMETER_TYPE, name ? name : "null", "string"); return; } *obj = g_strdup(qstring_get_str(qobject_to_qstring(qobj))); }
/* test commands that return an error due to invalid parameters */ static void test_dispatch_cmd_error(void) { QDict *req = qdict_new(); QObject *resp; qdict_put_obj(req, "execute", QOBJECT(qstring_from_str("user_def_cmd2"))); resp = qmp_dispatch(QOBJECT(req)); assert(resp != NULL); assert(qdict_haskey(qobject_to_qdict(resp), "error")); g_print("\nresp: %s\n", qstring_get_str(qobject_to_json_pretty(resp))); qobject_decref(resp); QDECREF(req); }
/* test enum values */ static void test_enums(void) { QmpOutputVisitor *mo; QmpInputVisitor *mi; Visitor *v; EnumOne enum1 = ENUM_ONE_VALUE2, enum1_cpy = ENUM_ONE_VALUE1; Error *err = NULL; QObject *obj; QString *str; /* C type -> QObject */ mo = qmp_output_visitor_new(); v = qmp_output_get_visitor(mo); visit_type_EnumOne(v, &enum1, "unused", &err); if (err) { g_error("%s", error_get_pretty(err)); } obj = qmp_output_get_qobject(mo); g_assert(obj); str = qobject_to_json_pretty(obj); g_print("%s\n", qstring_get_str(str)); QDECREF(str); g_assert(g_strcmp0(qstring_get_str(qobject_to_qstring(obj)), "value2") == 0); /* QObject -> C type */ mi = qmp_input_visitor_new(obj); v = qmp_input_get_visitor(mi); visit_type_EnumOne(v, &enum1_cpy, "unused", &err); if (err) { g_error("%s", error_get_pretty(err)); } g_debug("enum1_cpy, enum1: %d, %d", enum1_cpy, enum1); g_assert(enum1_cpy == enum1); qobject_decref(obj); }
static const char *append_field(QDict *error, QString *outstr, const QErrorStringTable *entry, const char *start) { QObject *obj; QDict *qdict; QString *key_qs; const char *end, *key; if (*start != '%') parse_error(entry, '%'); start++; if (*start != '(') parse_error(entry, '('); start++; end = strchr(start, ')'); if (!end) parse_error(entry, ')'); key_qs = qstring_from_substr(start, 0, end - start - 1); key = qstring_get_str(key_qs); qdict = qobject_to_qdict(qdict_get(error, "data")); obj = qdict_get(qdict, key); if (!obj) { abort(); } switch (qobject_type(obj)) { case QTYPE_QSTRING: qstring_append(outstr, qdict_get_str(qdict, key)); break; case QTYPE_QINT: qstring_append_int(outstr, qdict_get_int(qdict, key)); break; default: abort(); } QDECREF(key_qs); return ++end; }
static const char *append_field(QString *outstr, const QError *qerror, const char *start) { QObject *obj; QDict *qdict; QString *key_qs; const char *end, *key; if (*start != '%') parse_error(qerror, '%'); start++; if (*start != '(') parse_error(qerror, '('); start++; end = strchr(start, ')'); if (!end) parse_error(qerror, ')'); key_qs = qstring_from_substr(start, 0, end - start - 1); key = qstring_get_str(key_qs); qdict = qobject_to_qdict(qdict_get(qerror->error, "data")); obj = qdict_get(qdict, key); if (!obj) { qerror_abort(qerror, "key '%s' not found in QDict", key); } switch (qobject_type(obj)) { case QTYPE_QSTRING: qstring_append(outstr, qdict_get_str(qdict, key)); break; case QTYPE_QINT: qstring_append_int(outstr, qdict_get_int(qdict, key)); break; default: qerror_abort(qerror, "invalid type '%c'", qobject_type(obj)); } QDECREF(key_qs); return ++end; }
const char *qjson_get_str(QJSON *json) { return qstring_get_str(json->str); }
static void qdict_stress_test(void) { size_t lines; char key[128]; FILE *test_file; QDict *qdict; QString *value; const char *test_file_path = "qdict-test-data.txt"; test_file = fopen(test_file_path, "r"); g_assert(test_file != NULL); // Create the dict qdict = qdict_new(); g_assert(qdict != NULL); // Add everything from the test file for (lines = 0;; lines++) { value = read_line(test_file, key); if (!value) break; qdict_put(qdict, key, value); } g_assert(qdict_size(qdict) == lines); // Check if everything is really in there reset_file(test_file); for (;;) { const char *str1, *str2; value = read_line(test_file, key); if (!value) break; str1 = qstring_get_str(value); str2 = qdict_get_str(qdict, key); g_assert(str2 != NULL); g_assert(strcmp(str1, str2) == 0); QDECREF(value); } // Delete everything reset_file(test_file); for (;;) { value = read_line(test_file, key); if (!value) break; qdict_del(qdict, key); QDECREF(value); g_assert(qdict_haskey(qdict, key) == 0); } fclose(test_file); g_assert(qdict_size(qdict) == 0); QDECREF(qdict); }
const char *qdict_get_str(const QDict *qdict, const char *key) { QObject *obj = qdict_get_obj(qdict, key, QTYPE_QSTRING); return qstring_get_str(qobject_to_qstring(obj)); }
static void to_json(const QObject *obj, QString *str) { switch (qobject_type(obj)) { case QTYPE_QINT: { QInt *val = qobject_to_qint(obj); char buffer[1024]; snprintf(buffer, sizeof(buffer), "%" PRId64, qint_get_int(val)); qstring_append(str, buffer); break; } case QTYPE_QSTRING: { QString *val = qobject_to_qstring(obj); const char *ptr; ptr = qstring_get_str(val); qstring_append(str, "\""); while (*ptr) { if ((ptr[0] & 0xE0) == 0xE0 && (ptr[1] & 0x80) && (ptr[2] & 0x80)) { uint16_t wchar; char escape[7]; wchar = (ptr[0] & 0x0F) << 12; wchar |= (ptr[1] & 0x3F) << 6; wchar |= (ptr[2] & 0x3F); ptr += 2; snprintf(escape, sizeof(escape), "\\u%04X", wchar); qstring_append(str, escape); } else if ((ptr[0] & 0xE0) == 0xC0 && (ptr[1] & 0x80)) { uint16_t wchar; char escape[7]; wchar = (ptr[0] & 0x1F) << 6; wchar |= (ptr[1] & 0x3F); ptr++; snprintf(escape, sizeof(escape), "\\u%04X", wchar); qstring_append(str, escape); } else switch (ptr[0]) { case '\"': qstring_append(str, "\\\""); break; case '\\': qstring_append(str, "\\\\"); break; case '\b': qstring_append(str, "\\b"); break; case '\f': qstring_append(str, "\\f"); break; case '\n': qstring_append(str, "\\n"); break; case '\r': qstring_append(str, "\\r"); break; case '\t': qstring_append(str, "\\t"); break; default: { if (ptr[0] <= 0x1F) { char escape[7]; snprintf(escape, sizeof(escape), "\\u%04X", ptr[0]); qstring_append(str, escape); } else { char buf[2] = { ptr[0], 0 }; qstring_append(str, buf); } break; } } ptr++; } qstring_append(str, "\""); break; } case QTYPE_QDICT: { ToJsonIterState s; QDict *val = qobject_to_qdict(obj); s.count = 0; s.str = str; qstring_append(str, "{"); qdict_iter(val, to_json_dict_iter, &s); qstring_append(str, "}"); break; } case QTYPE_QLIST: { ToJsonIterState s; QList *val = qobject_to_qlist(obj); s.count = 0; s.str = str; qstring_append(str, "["); qlist_iter(val, (void *)to_json_list_iter, &s); qstring_append(str, "]"); break; } case QTYPE_QFLOAT: { QFloat *val = qobject_to_qfloat(obj); char buffer[1024]; int len; len = snprintf(buffer, sizeof(buffer), "%f", qfloat_get_double(val)); while (len > 0 && buffer[len - 1] == '0') { len--; } if (len && buffer[len - 1] == '.') { buffer[len - 1] = 0; } else { buffer[len] = 0; } qstring_append(str, buffer); break; } case QTYPE_QBOOL: { QBool *val = qobject_to_qbool(obj); if (qbool_get_int(val)) { qstring_append(str, "true"); } else { qstring_append(str, "false"); } break; } case QTYPE_QERROR: /* XXX: should QError be emitted? */ case QTYPE_NONE: break; } }
/* test deep nesting with refs to other user-defined types */ static void test_nested_structs(void) { QmpOutputVisitor *mo; QmpInputVisitor *mi; Visitor *v; UserDefOne ud1; UserDefOne *ud1_p = &ud1, *ud1c_p = NULL; UserDefTwo ud2; UserDefTwo *ud2_p = &ud2, *ud2c_p = NULL; Error *err = NULL; QObject *obj; QString *str; ud1.integer = 42; ud1.string = strdup("fourty two"); /* sanity check */ mo = qmp_output_visitor_new(); v = qmp_output_get_visitor(mo); visit_type_UserDefOne(v, &ud1_p, "o_O", &err); if (err) { g_error("%s", error_get_pretty(err)); } obj = qmp_output_get_qobject(mo); g_assert(obj); qobject_decref(obj); ud2.string = strdup("fourty three"); ud2.dict.string = strdup("fourty four"); ud2.dict.dict.userdef = ud1_p; ud2.dict.dict.string = strdup("fourty five"); ud2.dict.has_dict2 = true; ud2.dict.dict2.userdef = ud1_p; ud2.dict.dict2.string = strdup("fourty six"); /* c type -> qobject */ mo = qmp_output_visitor_new(); v = qmp_output_get_visitor(mo); visit_type_UserDefTwo(v, &ud2_p, "unused", &err); if (err) { g_error("%s", error_get_pretty(err)); } obj = qmp_output_get_qobject(mo); g_assert(obj); str = qobject_to_json_pretty(obj); g_print("%s\n", qstring_get_str(str)); QDECREF(str); /* qobject -> c type, should match original struct */ mi = qmp_input_visitor_new(obj); v = qmp_input_get_visitor(mi); visit_type_UserDefTwo(v, &ud2c_p, NULL, &err); if (err) { g_error("%s", error_get_pretty(err)); } g_assert(!g_strcmp0(ud2c_p->string, ud2.string)); g_assert(!g_strcmp0(ud2c_p->dict.string, ud2.dict.string)); ud1c_p = ud2c_p->dict.dict.userdef; g_assert(ud1c_p->integer == ud1_p->integer); g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string)); g_assert(!g_strcmp0(ud2c_p->dict.dict.string, ud2.dict.dict.string)); ud1c_p = ud2c_p->dict.dict2.userdef; g_assert(ud1c_p->integer == ud1_p->integer); g_assert(!g_strcmp0(ud1c_p->string, ud1_p->string)); g_assert(!g_strcmp0(ud2c_p->dict.dict2.string, ud2.dict.dict2.string)); g_free(ud1.string); g_free(ud2.string); g_free(ud2.dict.string); g_free(ud2.dict.dict.string); g_free(ud2.dict.dict2.string); qapi_free_UserDefTwo(ud2c_p); qobject_decref(obj); }
/* test core visitor methods */ static void test_visitor_core(void) { QmpOutputVisitor *mo; QmpInputVisitor *mi; Visitor *v; TestStruct ts = { 42, 82 }; TestStruct *pts = &ts; TestStructList *lts = NULL; Error *err = NULL; QObject *obj; QList *qlist; QDict *qdict; QString *str; int64_t value = 0; mo = qmp_output_visitor_new(); v = qmp_output_get_visitor(mo); visit_type_TestStruct(v, &pts, NULL, &err); obj = qmp_output_get_qobject(mo); str = qobject_to_json(obj); printf("%s\n", qstring_get_str(str)); QDECREF(str); obj = QOBJECT(qint_from_int(0x42)); mi = qmp_input_visitor_new(obj); v = qmp_input_get_visitor(mi); visit_type_int(v, &value, NULL, &err); if (err) { g_error("%s", error_get_pretty(err)); } g_assert(value == 0x42); qobject_decref(obj); obj = qobject_from_json("{'x': 42, 'y': 84}"); mi = qmp_input_visitor_new(obj); v = qmp_input_get_visitor(mi); pts = NULL; visit_type_TestStruct(v, &pts, NULL, &err); if (err) { g_error("%s", error_get_pretty(err)); } g_assert(pts != NULL); g_assert(pts->x == 42); g_assert(pts->y == 84); qobject_decref(obj); g_free(pts); /* test list input visitor */ obj = qobject_from_json("[{'x': 42, 'y': 84}, {'x': 12, 'y': 24}]"); mi = qmp_input_visitor_new(obj); v = qmp_input_get_visitor(mi); visit_type_TestStructList(v, <s, NULL, &err); if (err) { g_error("%s", error_get_pretty(err)); } g_assert(lts != NULL); g_assert(lts->value->x == 42); g_assert(lts->value->y == 84); g_assert(lts->next != NULL); g_assert(lts->next->value->x == 12); g_assert(lts->next->value->y == 24); g_assert(lts->next->next == NULL); qobject_decref(obj); /* test list output visitor */ mo = qmp_output_visitor_new(); v = qmp_output_get_visitor(mo); visit_type_TestStructList(v, <s, NULL, &err); if (err) { g_error("%s", error_get_pretty(err)); } obj = qmp_output_get_qobject(mo); g_print("obj: %s\n", qstring_get_str(qobject_to_json(obj))); qlist = qobject_to_qlist(obj); assert(qlist); obj = qlist_pop(qlist); qdict = qobject_to_qdict(obj); assert(qdict); assert(qdict_get_int(qdict, "x") == 42); assert(qdict_get_int(qdict, "y") == 84); qobject_decref(obj); obj = qlist_pop(qlist); qdict = qobject_to_qdict(obj); assert(qdict); assert(qdict_get_int(qdict, "x") == 12); assert(qdict_get_int(qdict, "y") == 24); qobject_decref(obj); qmp_output_visitor_cleanup(mo); QDECREF(qlist); }
/** * qerror_print(): Print QError data * * This function will print the member 'desc' of the specified QError object, * it uses qemu_error() for this, so that the output is routed to the right * place (ie. stderr or Monitor's device). */ void qerror_print(const QError *qerror) { QString *qstring = qerror_human(qerror); qemu_error("%s\n", qstring_get_str(qstring)); QDECREF(qstring); }