qemu

FORK: QEMU emulator
git clone https://git.neptards.moe/neptards/qemu.git
Log | Files | Refs | Submodules | LICENSE

libqmp.c (5924B)


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