qemu/tests/qtest/libqmp.c
<<
>>
Prefs
   1/*
   2 * QTest
   3 *
   4 * Copyright IBM, Corp. 2012
   5 * Copyright Red Hat, Inc. 2012
   6 * Copyright SUSE LINUX Products GmbH 2013
   7 *
   8 * Authors:
   9 *  Anthony Liguori   <aliguori@us.ibm.com>
  10 *  Paolo Bonzini     <pbonzini@redhat.com>
  11 *  Andreas Färber    <afaerber@suse.de>
  12 *
  13 * This work is licensed under the terms of the GNU GPL, version 2 or later.
  14 * See the COPYING file in the top-level directory.
  15 */
  16
  17#include "qemu/osdep.h"
  18
  19#include "libqmp.h"
  20
  21#ifndef _WIN32
  22#include <sys/socket.h>
  23#endif
  24
  25#include "qemu/cutils.h"
  26#include "qapi/error.h"
  27#include "qapi/qmp/json-parser.h"
  28#include "qapi/qmp/qjson.h"
  29
  30#define SOCKET_MAX_FDS 16
  31
  32typedef struct {
  33    JSONMessageParser parser;
  34    QDict *response;
  35} QMPResponseParser;
  36
  37static void socket_send(int fd, const char *buf, size_t size)
  38{
  39    size_t res = qemu_write_full(fd, buf, size);
  40
  41    assert(res == size);
  42}
  43
  44static void qmp_response(void *opaque, QObject *obj, Error *err)
  45{
  46    QMPResponseParser *qmp = opaque;
  47
  48    assert(!obj != !err);
  49
  50    if (err) {
  51        error_prepend(&err, "QMP JSON response parsing failed: ");
  52        error_report_err(err);
  53        abort();
  54    }
  55
  56    g_assert(!qmp->response);
  57    qmp->response = qobject_to(QDict, obj);
  58    g_assert(qmp->response);
  59}
  60
  61QDict *qmp_fd_receive(int fd)
  62{
  63    QMPResponseParser qmp;
  64    bool log = getenv("QTEST_LOG") != NULL;
  65
  66    qmp.response = NULL;
  67    json_message_parser_init(&qmp.parser, qmp_response, &qmp, NULL);
  68    while (!qmp.response) {
  69        ssize_t len;
  70        char c;
  71
  72        len = read(fd, &c, 1);
  73        if (len == -1 && errno == EINTR) {
  74            continue;
  75        }
  76
  77        if (len == -1 || len == 0) {
  78            fprintf(stderr, "Broken pipe\n");
  79            abort();
  80        }
  81
  82        if (log) {
  83            g_assert(write(2, &c, 1) == 1);
  84        }
  85        json_message_parser_feed(&qmp.parser, &c, 1);
  86    }
  87    if (log) {
  88        g_assert(write(2, "\n", 1) == 1);
  89    }
  90    json_message_parser_destroy(&qmp.parser);
  91
  92    return qmp.response;
  93}
  94
  95#ifndef _WIN32
  96/* Sends a message and file descriptors to the socket.
  97 * It's needed for qmp-commands like getfd/add-fd */
  98static void socket_send_fds(int socket_fd, int *fds, size_t fds_num,
  99                            const char *buf, size_t buf_size)
 100{
 101    ssize_t ret;
 102    struct msghdr msg = { 0 };
 103    char control[CMSG_SPACE(sizeof(int) * SOCKET_MAX_FDS)] = { 0 };
 104    size_t fdsize = sizeof(int) * fds_num;
 105    struct cmsghdr *cmsg;
 106    struct iovec iov = { .iov_base = (char *)buf, .iov_len = buf_size };
 107
 108    msg.msg_iov = &iov;
 109    msg.msg_iovlen = 1;
 110
 111    if (fds && fds_num > 0) {
 112        g_assert_cmpuint(fds_num, <, SOCKET_MAX_FDS);
 113
 114        msg.msg_control = control;
 115        msg.msg_controllen = CMSG_SPACE(fdsize);
 116
 117        cmsg = CMSG_FIRSTHDR(&msg);
 118        cmsg->cmsg_len = CMSG_LEN(fdsize);
 119        cmsg->cmsg_level = SOL_SOCKET;
 120        cmsg->cmsg_type = SCM_RIGHTS;
 121        memcpy(CMSG_DATA(cmsg), fds, fdsize);
 122    }
 123
 124    do {
 125        ret = sendmsg(socket_fd, &msg, 0);
 126    } while (ret < 0 && errno == EINTR);
 127    g_assert_cmpint(ret, >, 0);
 128}
 129#endif
 130
 131/**
 132 * Allow users to send a message without waiting for the reply,
 133 * in the case that they choose to discard all replies up until
 134 * a particular EVENT is received.
 135 */
 136static void
 137_qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
 138                  const char *fmt, va_list ap)
 139{
 140    QObject *qobj;
 141
 142#ifdef _WIN32
 143    assert(fds_num == 0);
 144#endif
 145
 146    /* Going through qobject ensures we escape strings properly */
 147    qobj = qobject_from_vjsonf_nofail(fmt, ap);
 148
 149    /* No need to send anything for an empty QObject.  */
 150    if (qobj) {
 151        int log = getenv("QTEST_LOG") != NULL;
 152        GString *str = qobject_to_json(qobj);
 153
 154        /*
 155         * BUG: QMP doesn't react to input until it sees a newline, an
 156         * object, or an array.  Work-around: give it a newline.
 157         */
 158        g_string_append_c(str, '\n');
 159
 160        if (log) {
 161            fprintf(stderr, "%s", str->str);
 162        }
 163
 164#ifndef _WIN32
 165        /* Send QMP request */
 166        if (fds && fds_num > 0) {
 167            socket_send_fds(fd, fds, fds_num, str->str, str->len);
 168        } else
 169#endif
 170        {
 171            socket_send(fd, str->str, str->len);
 172        }
 173
 174        g_string_free(str, true);
 175        qobject_unref(qobj);
 176    }
 177}
 178
 179#ifndef _WIN32
 180void qmp_fd_vsend_fds(int fd, int *fds, size_t fds_num,
 181                      const char *fmt, va_list ap)
 182{
 183    _qmp_fd_vsend_fds(fd, fds, fds_num, fmt, ap);
 184}
 185#endif
 186
 187void qmp_fd_vsend(int fd, const char *fmt, va_list ap)
 188{
 189    _qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
 190}
 191
 192
 193QDict *qmp_fdv(int fd, const char *fmt, va_list ap)
 194{
 195    _qmp_fd_vsend_fds(fd, NULL, 0, fmt, ap);
 196
 197    return qmp_fd_receive(fd);
 198}
 199
 200QDict *qmp_fd(int fd, const char *fmt, ...)
 201{
 202    va_list ap;
 203    QDict *response;
 204
 205    va_start(ap, fmt);
 206    response = qmp_fdv(fd, fmt, ap);
 207    va_end(ap);
 208    return response;
 209}
 210
 211void qmp_fd_send(int fd, const char *fmt, ...)
 212{
 213    va_list ap;
 214
 215    va_start(ap, fmt);
 216    qmp_fd_vsend(fd, fmt, ap);
 217    va_end(ap);
 218}
 219
 220void qmp_fd_vsend_raw(int fd, const char *fmt, va_list ap)
 221{
 222    bool log = getenv("QTEST_LOG") != NULL;
 223    char *str = g_strdup_vprintf(fmt, ap);
 224
 225    if (log) {
 226        fprintf(stderr, "%s", str);
 227    }
 228    socket_send(fd, str, strlen(str));
 229    g_free(str);
 230}
 231
 232void qmp_fd_send_raw(int fd, const char *fmt, ...)
 233{
 234    va_list ap;
 235
 236    va_start(ap, fmt);
 237    qmp_fd_vsend_raw(fd, fmt, ap);
 238    va_end(ap);
 239}
 240
 241bool qmp_rsp_is_err(QDict *rsp)
 242{
 243    QDict *error = qdict_get_qdict(rsp, "error");
 244    qobject_unref(rsp);
 245    return !!error;
 246}
 247
 248void qmp_expect_error_and_unref(QDict *rsp, const char *class)
 249{
 250    QDict *error = qdict_get_qdict(rsp, "error");
 251
 252    g_assert_cmpstr(qdict_get_try_str(error, "class"), ==, class);
 253    g_assert_nonnull(qdict_get_try_str(error, "desc"));
 254    g_assert(!qdict_haskey(rsp, "return"));
 255
 256    qobject_unref(rsp);
 257}
 258