1 /*
2  * Copyright (C) 2011      Citrix Ltd.
3  * Author Anthony PERARD <anthony.perard@citrix.com>
4  *
5  * This program is free software; you can redistribute it and/or modify
6  * it under the terms of the GNU Lesser General Public License as published
7  * by the Free Software Foundation; version 2.1 only. with the special
8  * exception on linking described in file LICENSE.
9  *
10  * This program is distributed in the hope that it will be useful,
11  * but WITHOUT ANY WARRANTY; without even the implied warranty of
12  * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
13  * GNU Lesser General Public License for more details.
14  */
15 
16 /*
17  * This file implement a client for QMP (QEMU Monitor Protocol). For the
18  * Specification, see in the QEMU repository.
19  *
20  * WARNING - Do not trust QEMU when writing codes for new commands or when
21  *           improving the client code.
22  */
23 
24 /*
25  * Logic used to send command to QEMU
26  *
27  * qmp_open():
28  *  Will open a socket and connect to QEMU.
29  *
30  * qmp_next():
31  *  Will read data sent by QEMU and then call qmp_handle_response() once a
32  *  complete QMP message is received.
33  *  The function return on timeout/error or once every data received as been
34  *  processed.
35  *
36  * qmp_handle_response()
37  *  This process json messages received from QEMU and update different list and
38  *  may call callback function.
39  *  `libxl__qmp_handler.wait_for_id` is reset once a message with this ID is
40  *    processed.
41  *  `libxl__qmp_handler.callback_list`: list with ID of command sent and
42  *    optional assotiated callback function. The return value of a callback is
43  *    set in context.
44  *
45  * qmp_send():
46  *  Simply prepare a QMP command and send it to QEMU.
47  *  It also add a `struct callback_id_pair` on the
48  *  `libxl__qmp_handler.callback_list` via qmp_send_prepare().
49  *
50  * qmp_synchronous_send():
51  *  This function calls qmp_send(), then wait for QEMU to reply to the command.
52  *  The wait is done by calling qmp_next() over and over again until either
53  *  there is a response for the command or there is an error.
54  *
55  *  An ID can be set for each QMP command, this is set into
56  *  `libxl__qmp_handler.wait_for_id`. qmp_next will check every response's ID
57  *  again this field and change the value of the field once the ID is found.
58  */
59 
60 #include "libxl_osdeps.h" /* must come before any other headers */
61 
62 #include <sys/un.h>
63 
64 #include <yajl/yajl_gen.h>
65 
66 #include "_libxl_list.h"
67 #include "libxl_internal.h"
68 
69 /* #define DEBUG_RECEIVED */
70 
71 #ifdef DEBUG_RECEIVED
72 #  define DEBUG_REPORT_RECEIVED(dom, buf, len) \
73     LOGD(DEBUG, dom, "received: '%.*s'", len, buf)
74 #else
75 #  define DEBUG_REPORT_RECEIVED(dom, buf, len) ((void)0)
76 #endif
77 
78 #ifdef DEBUG_QMP_CLIENT
79 #  define LOG_QMP(f, ...) LOGD(DEBUG, ev->domid, f, ##__VA_ARGS__)
80 #else
81 #  define LOG_QMP(f, ...)
82 #endif
83 
84 /*
85  * QMP types & constant
86  */
87 
88 #define QMP_RECEIVE_BUFFER_SIZE 4096
89 #define QMP_MAX_SIZE_RX_BUF MB(1)
90 
91 /*
92  * qmp_callback_t is call whenever a message from QMP contain the "id"
93  * associated with the callback.
94  * "tree" contain the JSON tree that is in "return" of a QMP message. If QMP
95  * sent an error message, "tree" will be NULL.
96  */
97 typedef int (*qmp_callback_t)(libxl__qmp_handler *qmp,
98                               const libxl__json_object *tree,
99                               void *opaque);
100 
101 typedef struct qmp_request_context {
102     int rc;
103 } qmp_request_context;
104 
105 typedef struct callback_id_pair {
106     int id;
107     qmp_callback_t callback;
108     void *opaque;
109     qmp_request_context *context;
110     LIBXL_STAILQ_ENTRY(struct callback_id_pair) next;
111 } callback_id_pair;
112 
113 struct libxl__qmp_handler {
114     int qmp_fd;
115     bool connected;
116     time_t timeout;
117     /* wait_for_id will be used by the synchronous send function */
118     int wait_for_id;
119 
120     char buffer[QMP_RECEIVE_BUFFER_SIZE + 1];
121 
122     libxl_ctx *ctx;
123     uint32_t domid;
124 
125     int last_id_used;
126     LIBXL_STAILQ_HEAD(callback_list, callback_id_pair) callback_list;
127     struct {
128         int major;
129         int minor;
130         int micro;
131     } version;
132 };
133 
134 static int qmp_send(libxl__qmp_handler *qmp,
135                     const char *cmd, libxl__json_object *args,
136                     qmp_callback_t callback, void *opaque,
137                     qmp_request_context *context);
138 
139 static const int QMP_SOCKET_CONNECT_TIMEOUT = 5;
140 
141 /*
142  * QMP callbacks functions
143  */
144 
qmp_capabilities_callback(libxl__qmp_handler * qmp,const libxl__json_object * o,void * unused)145 static int qmp_capabilities_callback(libxl__qmp_handler *qmp,
146                                      const libxl__json_object *o, void *unused)
147 {
148     qmp->connected = true;
149 
150     return 0;
151 }
152 
153 /*
154  * QMP commands
155  */
156 
enable_qmp_capabilities(libxl__qmp_handler * qmp)157 static int enable_qmp_capabilities(libxl__qmp_handler *qmp)
158 {
159     return qmp_send(qmp, "qmp_capabilities", NULL,
160                     qmp_capabilities_callback, NULL, NULL);
161 }
162 
163 /*
164  * Helpers
165  */
166 
qmp_response_type(const libxl__json_object * o)167 static libxl__qmp_message_type qmp_response_type(const libxl__json_object *o)
168 {
169     libxl__qmp_message_type type;
170     libxl__json_map_node *node = NULL;
171     int i = 0;
172 
173     for (i = 0; (node = libxl__json_map_node_get(o, i)); i++) {
174         if (libxl__qmp_message_type_from_string(node->map_key, &type) == 0)
175             return type;
176     }
177 
178     return LIBXL__QMP_MESSAGE_TYPE_INVALID;
179 }
180 
qmp_get_callback_from_id(libxl__qmp_handler * qmp,const libxl__json_object * o)181 static callback_id_pair *qmp_get_callback_from_id(libxl__qmp_handler *qmp,
182                                                   const libxl__json_object *o)
183 {
184     const libxl__json_object *id_object = libxl__json_map_get("id", o,
185                                                               JSON_INTEGER);
186     int id = -1;
187     callback_id_pair *pp = NULL;
188 
189     if (id_object) {
190         id = libxl__json_object_get_integer(id_object);
191 
192         LIBXL_STAILQ_FOREACH(pp, &qmp->callback_list, next) {
193             if (pp->id == id) {
194                 return pp;
195             }
196         }
197     }
198     return NULL;
199 }
200 
qmp_handle_error_response(libxl__gc * gc,libxl__qmp_handler * qmp,const libxl__json_object * resp)201 static void qmp_handle_error_response(libxl__gc *gc, libxl__qmp_handler *qmp,
202                                       const libxl__json_object *resp)
203 {
204     callback_id_pair *pp = qmp_get_callback_from_id(qmp, resp);
205 
206     resp = libxl__json_map_get("error", resp, JSON_MAP);
207     resp = libxl__json_map_get("desc", resp, JSON_STRING);
208 
209     if (pp) {
210         if (pp->callback) {
211             int rc = pp->callback(qmp, NULL, pp->opaque);
212             if (pp->context) {
213                 pp->context->rc = rc;
214             }
215         }
216         if (pp->id == qmp->wait_for_id) {
217             /* tell that the id have been processed */
218             qmp->wait_for_id = 0;
219         }
220         LIBXL_STAILQ_REMOVE(&qmp->callback_list, pp, callback_id_pair, next);
221         free(pp);
222     }
223 
224     LOGD(ERROR, qmp->domid, "received an error message from QMP server: %s",
225          libxl__json_object_get_string(resp));
226 }
227 
qmp_handle_response(libxl__gc * gc,libxl__qmp_handler * qmp,const libxl__json_object * resp)228 static int qmp_handle_response(libxl__gc *gc, libxl__qmp_handler *qmp,
229                                const libxl__json_object *resp)
230 {
231     libxl__qmp_message_type type = LIBXL__QMP_MESSAGE_TYPE_INVALID;
232 
233     type = qmp_response_type(resp);
234     LOGD(DEBUG, qmp->domid, "message type: %s", libxl__qmp_message_type_to_string(type));
235 
236     switch (type) {
237     case LIBXL__QMP_MESSAGE_TYPE_QMP: {
238         const libxl__json_object *o;
239         o = libxl__json_map_get("QMP", resp, JSON_MAP);
240         o = libxl__json_map_get("version", o, JSON_MAP);
241         o = libxl__json_map_get("qemu", o, JSON_MAP);
242         qmp->version.major = libxl__json_object_get_integer(
243             libxl__json_map_get("major", o, JSON_INTEGER));
244         qmp->version.minor = libxl__json_object_get_integer(
245             libxl__json_map_get("minor", o, JSON_INTEGER));
246         qmp->version.micro = libxl__json_object_get_integer(
247             libxl__json_map_get("micro", o, JSON_INTEGER));
248         LOGD(DEBUG, qmp->domid, "QEMU version: %d.%d.%d",
249              qmp->version.major, qmp->version.minor, qmp->version.micro);
250         /* On the greeting message from the server, enable QMP capabilities */
251         return enable_qmp_capabilities(qmp);
252     }
253     case LIBXL__QMP_MESSAGE_TYPE_RETURN: {
254         callback_id_pair *pp = qmp_get_callback_from_id(qmp, resp);
255 
256         if (pp) {
257             if (pp->callback) {
258                 int rc = pp->callback(qmp,
259                              libxl__json_map_get("return", resp, JSON_ANY),
260                              pp->opaque);
261                 if (pp->context) {
262                     pp->context->rc = rc;
263                 }
264             }
265             if (pp->id == qmp->wait_for_id) {
266                 /* tell that the id have been processed */
267                 qmp->wait_for_id = 0;
268             }
269             LIBXL_STAILQ_REMOVE(&qmp->callback_list, pp, callback_id_pair,
270                                 next);
271             free(pp);
272         }
273         return 0;
274     }
275     case LIBXL__QMP_MESSAGE_TYPE_ERROR:
276         qmp_handle_error_response(gc, qmp, resp);
277         return -1;
278     case LIBXL__QMP_MESSAGE_TYPE_EVENT:
279         return 0;
280     case LIBXL__QMP_MESSAGE_TYPE_INVALID:
281         return -1;
282     }
283     return 0;
284 }
285 
286 /*
287  * return values:
288  *   < 0  if qemu's version <  asked version
289  *   = 0  if qemu's version == asked version
290  *   > 0  if qemu's version >  asked version
291  */
qmp_ev_qemu_compare_version(libxl__ev_qmp * ev,int major,int minor,int micro)292 static int qmp_ev_qemu_compare_version(libxl__ev_qmp *ev, int major,
293                                        int minor, int micro)
294 {
295 #define CHECK_VERSION(level) do { \
296     if (ev->qemu_version.level > (level)) return +1; \
297     if (ev->qemu_version.level < (level)) return -1; \
298 } while (0)
299 
300     CHECK_VERSION(major);
301     CHECK_VERSION(minor);
302     CHECK_VERSION(micro);
303 
304 #undef CHECK_VERSION
305 
306     return 0;
307 }
308 
309 /*
310  * Handler functions
311  */
312 
qmp_init_handler(libxl__gc * gc,uint32_t domid)313 static libxl__qmp_handler *qmp_init_handler(libxl__gc *gc, uint32_t domid)
314 {
315     libxl__qmp_handler *qmp = NULL;
316 
317     qmp = calloc(1, sizeof (libxl__qmp_handler));
318     if (qmp == NULL) {
319         LOGED(ERROR, domid, "Failed to allocate qmp_handler");
320         return NULL;
321     }
322     qmp->ctx = CTX;
323     qmp->domid = domid;
324     qmp->timeout = 5;
325 
326     LIBXL_STAILQ_INIT(&qmp->callback_list);
327 
328     return qmp;
329 }
330 
qmp_open(libxl__qmp_handler * qmp,const char * qmp_socket_path,int timeout)331 static int qmp_open(libxl__qmp_handler *qmp, const char *qmp_socket_path,
332                     int timeout)
333 {
334     GC_INIT(qmp->ctx);
335     int ret = -1;
336     int i = 0;
337     struct sockaddr_un addr;
338 
339     qmp->qmp_fd = socket(AF_UNIX, SOCK_STREAM, 0);
340     if (qmp->qmp_fd < 0) {
341         goto out;
342     }
343     ret = libxl_fd_set_nonblock(qmp->ctx, qmp->qmp_fd, 1);
344     if (ret) {
345         ret = -1;
346         goto out;
347     }
348     ret = libxl_fd_set_cloexec(qmp->ctx, qmp->qmp_fd, 1);
349     if (ret) {
350         ret = -1;
351         goto out;
352     }
353 
354     ret = libxl__prepare_sockaddr_un(gc, &addr, qmp_socket_path, "QMP socket");
355     if (ret)
356         goto out;
357 
358     do {
359         ret = connect(qmp->qmp_fd, (struct sockaddr *) &addr, sizeof(addr));
360         if (ret == 0)
361             break;
362         if (errno == ENOENT || errno == ECONNREFUSED) {
363             /* ENOENT       : Socket may not have shown up yet
364              * ECONNREFUSED : Leftover socket hasn't been removed yet */
365             continue;
366         }
367         ret = -1;
368         goto out;
369     } while ((++i / 5 <= timeout) && (usleep(200 * 1000) <= 0));
370 
371 out:
372     if (ret == -1 && qmp->qmp_fd > -1) close(qmp->qmp_fd);
373 
374     GC_FREE;
375     return ret;
376 }
377 
qmp_close(libxl__qmp_handler * qmp)378 static void qmp_close(libxl__qmp_handler *qmp)
379 {
380     callback_id_pair *pp = NULL;
381     callback_id_pair *tmp = NULL;
382 
383     close(qmp->qmp_fd);
384     LIBXL_STAILQ_FOREACH(pp, &qmp->callback_list, next) {
385         free(tmp);
386         tmp = pp;
387     }
388     free(tmp);
389 }
390 
qmp_next(libxl__gc * gc,libxl__qmp_handler * qmp)391 static int qmp_next(libxl__gc *gc, libxl__qmp_handler *qmp)
392 {
393     ssize_t rd;
394     char *s = NULL;
395     char *s_end = NULL;
396 
397     char *incomplete = NULL;
398     size_t incomplete_size = 0;
399     int rc = 0;
400 
401     do {
402         fd_set rfds;
403         int ret = 0;
404         struct timeval timeout = {
405             .tv_sec = qmp->timeout,
406             .tv_usec = 0,
407         };
408 
409         FD_ZERO(&rfds);
410         FD_SET(qmp->qmp_fd, &rfds);
411 
412         ret = select(qmp->qmp_fd + 1, &rfds, NULL, NULL, &timeout);
413         if (ret == 0) {
414             LOGD(ERROR, qmp->domid, "timeout");
415             return -1;
416         } else if (ret < 0) {
417             if (errno == EINTR)
418                 continue;
419             LOGED(ERROR, qmp->domid, "Select error");
420             return -1;
421         }
422 
423         rd = read(qmp->qmp_fd, qmp->buffer, QMP_RECEIVE_BUFFER_SIZE);
424         if (rd == 0) {
425             LOGD(ERROR, qmp->domid, "Unexpected end of socket");
426             return -1;
427         } else if (rd < 0) {
428             LOGED(ERROR, qmp->domid, "Socket read error");
429             return rd;
430         }
431         qmp->buffer[rd] = '\0';
432 
433         DEBUG_REPORT_RECEIVED(qmp->domid, qmp->buffer, (int)rd);
434 
435         if (incomplete) {
436             size_t current_pos = s - incomplete;
437             incomplete = libxl__realloc(gc, incomplete,
438                                         incomplete_size + rd + 1);
439             strncat(incomplete + incomplete_size, qmp->buffer, rd);
440             s = incomplete + current_pos;
441             incomplete_size += rd;
442             s_end = incomplete + incomplete_size;
443         } else {
444             incomplete = libxl__strndup(gc, qmp->buffer, rd);
445             incomplete_size = rd;
446             s = incomplete;
447             s_end = s + rd;
448             rd = 0;
449         }
450 
451         do {
452             char *end = NULL;
453 
454             end = strstr(s, "\r\n");
455             if (end) {
456                 libxl__json_object *o = NULL;
457 
458                 *end = '\0';
459 
460                 o = libxl__json_parse(gc, s);
461 
462                 if (o) {
463                     rc = qmp_handle_response(gc, qmp, o);
464                 } else {
465                     LOGD(ERROR, qmp->domid, "Parse error of : %s", s);
466                     return -1;
467                 }
468 
469                 s = end + 2;
470             } else {
471                 break;
472             }
473         } while (s < s_end);
474     } while (s < s_end);
475 
476     return rc;
477 }
478 
qmp_prepare_cmd(libxl__gc * gc,const char * cmd,const libxl__json_object * args,int id)479 static char *qmp_prepare_cmd(libxl__gc *gc, const char *cmd,
480                              const libxl__json_object *args,
481                              int id)
482 {
483     yajl_gen hand = NULL;
484     /* memory for 'buf' is owned by 'hand' */
485     const unsigned char *buf;
486     libxl_yajl_length len;
487     yajl_gen_status s;
488     char *ret = NULL;
489 
490     hand = libxl_yajl_gen_alloc(NULL);
491 
492     if (!hand) {
493         return NULL;
494     }
495 
496 #if HAVE_YAJL_V2
497     /* Disable beautify for data sent to QEMU */
498     yajl_gen_config(hand, yajl_gen_beautify, 0);
499 #endif
500 
501     yajl_gen_map_open(hand);
502     libxl__yajl_gen_asciiz(hand, "execute");
503     libxl__yajl_gen_asciiz(hand, cmd);
504     libxl__yajl_gen_asciiz(hand, "id");
505     yajl_gen_integer(hand, id);
506     if (args) {
507         libxl__yajl_gen_asciiz(hand, "arguments");
508         libxl__json_object_to_yajl_gen(gc, hand, args);
509     }
510     yajl_gen_map_close(hand);
511 
512     s = yajl_gen_get_buf(hand, &buf, &len);
513 
514     if (s != yajl_gen_status_ok)
515         goto out;
516 
517     ret = libxl__sprintf(gc, "%*.*s\r\n", (int)len, (int)len, buf);
518 
519 out:
520     yajl_gen_free(hand);
521     return ret;
522 }
523 
qmp_send_prepare(libxl__gc * gc,libxl__qmp_handler * qmp,const char * cmd,libxl__json_object * args,qmp_callback_t callback,void * opaque,qmp_request_context * context)524 static char *qmp_send_prepare(libxl__gc *gc, libxl__qmp_handler *qmp,
525                               const char *cmd, libxl__json_object *args,
526                               qmp_callback_t callback, void *opaque,
527                               qmp_request_context *context)
528 {
529     char *buf;
530     callback_id_pair *elm;
531 
532     buf = qmp_prepare_cmd(gc, cmd, args, ++qmp->last_id_used);
533 
534     if (!buf) {
535         LOGD(ERROR, qmp->domid, "Failed to generate a qmp command");
536         goto out;
537     }
538 
539     elm = malloc(sizeof (callback_id_pair));
540     if (elm == NULL) {
541         LOGED(ERROR, qmp->domid, "Failed to allocate a QMP callback");
542         goto out;
543     }
544     elm->id = qmp->last_id_used;
545     elm->callback = callback;
546     elm->opaque = opaque;
547     elm->context = context;
548     LIBXL_STAILQ_INSERT_TAIL(&qmp->callback_list, elm, next);
549 
550     LOGD(DEBUG, qmp->domid, "next qmp command: '%s'", buf);
551 
552 out:
553     return buf;
554 }
555 
qmp_send(libxl__qmp_handler * qmp,const char * cmd,libxl__json_object * args,qmp_callback_t callback,void * opaque,qmp_request_context * context)556 static int qmp_send(libxl__qmp_handler *qmp,
557                     const char *cmd, libxl__json_object *args,
558                     qmp_callback_t callback, void *opaque,
559                     qmp_request_context *context)
560 {
561     char *buf = NULL;
562     int rc = -1;
563     GC_INIT(qmp->ctx);
564 
565     buf = qmp_send_prepare(gc, qmp, cmd, args, callback, opaque, context);
566 
567     if (buf == NULL) {
568         goto out;
569     }
570 
571     if (libxl_write_exactly(qmp->ctx, qmp->qmp_fd, buf, strlen(buf),
572                             "QMP command", "QMP socket"))
573         goto out;
574 
575     rc = qmp->last_id_used;
576 out:
577     GC_FREE;
578     return rc;
579 }
580 
qmp_synchronous_send(libxl__qmp_handler * qmp,const char * cmd,libxl__json_object * args,qmp_callback_t callback,void * opaque,int ask_timeout)581 static int qmp_synchronous_send(libxl__qmp_handler *qmp, const char *cmd,
582                                 libxl__json_object *args,
583                                 qmp_callback_t callback, void *opaque,
584                                 int ask_timeout)
585 {
586     int id = 0;
587     int ret = 0;
588     GC_INIT(qmp->ctx);
589     qmp_request_context context = { .rc = 0 };
590 
591     id = qmp_send(qmp, cmd, args, callback, opaque, &context);
592     if (id <= 0) {
593         return ERROR_FAIL;
594     }
595     qmp->wait_for_id = id;
596 
597     while (qmp->wait_for_id == id) {
598         if ((ret = qmp_next(gc, qmp)) < 0) {
599             break;
600         }
601     }
602 
603     if (qmp->wait_for_id != id && ret == 0) {
604         ret = context.rc;
605     }
606 
607     GC_FREE;
608 
609     return ret;
610 }
611 
qmp_free_handler(libxl__qmp_handler * qmp)612 static void qmp_free_handler(libxl__qmp_handler *qmp)
613 {
614     free(qmp);
615 }
616 
617 /*
618  * QMP Parameters Helpers
619  */
qmp_parameters_common_add(libxl__gc * gc,libxl__json_object ** param,const char * name,libxl__json_object * obj)620 static void qmp_parameters_common_add(libxl__gc *gc,
621                                       libxl__json_object **param,
622                                       const char *name,
623                                       libxl__json_object *obj)
624 {
625     libxl__json_map_node *arg = NULL;
626 
627     if (!*param) {
628         *param = libxl__json_object_alloc(gc, JSON_MAP);
629     }
630 
631     GCNEW(arg);
632 
633     arg->map_key = libxl__strdup(gc, name);
634     arg->obj = obj;
635 
636     flexarray_append((*param)->u.map, arg);
637 }
638 
libxl__qmp_param_add_string(libxl__gc * gc,libxl__json_object ** param,const char * name,const char * argument)639 void libxl__qmp_param_add_string(libxl__gc *gc,
640                                  libxl__json_object **param,
641                                  const char *name, const char *argument)
642 {
643     libxl__json_object *obj;
644 
645     obj = libxl__json_object_alloc(gc, JSON_STRING);
646     obj->u.string = libxl__strdup(gc, argument);
647 
648     qmp_parameters_common_add(gc, param, name, obj);
649 }
650 
libxl__qmp_param_add_bool(libxl__gc * gc,libxl__json_object ** param,const char * name,bool b)651 void libxl__qmp_param_add_bool(libxl__gc *gc,
652                                libxl__json_object **param,
653                                const char *name, bool b)
654 {
655     libxl__json_object *obj;
656 
657     obj = libxl__json_object_alloc(gc, JSON_BOOL);
658     obj->u.b = b;
659     qmp_parameters_common_add(gc, param, name, obj);
660 }
661 
libxl__qmp_param_add_integer(libxl__gc * gc,libxl__json_object ** param,const char * name,const int i)662 void libxl__qmp_param_add_integer(libxl__gc *gc,
663                                   libxl__json_object **param,
664                                   const char *name, const int i)
665 {
666     libxl__json_object *obj;
667 
668     obj = libxl__json_object_alloc(gc, JSON_INTEGER);
669     obj->u.i = i;
670 
671     qmp_parameters_common_add(gc, param, name, obj);
672 }
673 
674 /*
675  * API
676  */
677 
libxl__qmp_initialize(libxl__gc * gc,uint32_t domid)678 libxl__qmp_handler *libxl__qmp_initialize(libxl__gc *gc, uint32_t domid)
679 {
680     int ret = 0;
681     libxl__qmp_handler *qmp = NULL;
682     char *qmp_socket;
683 
684     qmp = qmp_init_handler(gc, domid);
685     if (!qmp) return NULL;
686 
687     qmp_socket = GCSPRINTF("%s/qmp-libxl-%d", libxl__run_dir_path(), domid);
688     if ((ret = qmp_open(qmp, qmp_socket, QMP_SOCKET_CONNECT_TIMEOUT)) < 0) {
689         LOGED(ERROR, domid, "Connection error");
690         qmp_free_handler(qmp);
691         return NULL;
692     }
693 
694     LOGD(DEBUG, domid, "connected to %s", qmp_socket);
695 
696     /* Wait for the response to qmp_capabilities */
697     while (!qmp->connected) {
698         if ((ret = qmp_next(gc, qmp)) < 0) {
699             break;
700         }
701     }
702 
703     if (!qmp->connected) {
704         LOGD(ERROR, domid, "Failed to connect to QMP");
705         libxl__qmp_close(qmp);
706         return NULL;
707     }
708     return qmp;
709 }
710 
libxl__qmp_close(libxl__qmp_handler * qmp)711 void libxl__qmp_close(libxl__qmp_handler *qmp)
712 {
713     if (!qmp)
714         return;
715     qmp_close(qmp);
716     qmp_free_handler(qmp);
717 }
718 
libxl__qmp_cleanup(libxl__gc * gc,uint32_t domid)719 void libxl__qmp_cleanup(libxl__gc *gc, uint32_t domid)
720 {
721     char *qmp_socket;
722 
723     qmp_socket = GCSPRINTF("%s/qmp-libxl-%d", libxl__run_dir_path(), domid);
724     if (unlink(qmp_socket) == -1) {
725         if (errno != ENOENT) {
726             LOGED(ERROR, domid, "Failed to remove QMP socket file %s", qmp_socket);
727         }
728     }
729 
730     qmp_socket = GCSPRINTF("%s/qmp-libxenstat-%d", libxl__run_dir_path(), domid);
731     if (unlink(qmp_socket) == -1) {
732         if (errno != ENOENT) {
733             LOGED(ERROR, domid, "Failed to remove QMP socket file %s", qmp_socket);
734         }
735     }
736 }
737 
qmp_run_command(libxl__gc * gc,int domid,const char * cmd,libxl__json_object * args,qmp_callback_t callback,void * opaque)738 static int qmp_run_command(libxl__gc *gc, int domid,
739                            const char *cmd, libxl__json_object *args,
740                            qmp_callback_t callback, void *opaque)
741 {
742     libxl__qmp_handler *qmp = NULL;
743     int rc = 0;
744 
745     qmp = libxl__qmp_initialize(gc, domid);
746     if (!qmp)
747         return ERROR_FAIL;
748 
749     rc = qmp_synchronous_send(qmp, cmd, args, callback, opaque, qmp->timeout);
750 
751     libxl__qmp_close(qmp);
752     return rc;
753 }
754 
libxl__qmp_restore(libxl__gc * gc,int domid,const char * state_file)755 int libxl__qmp_restore(libxl__gc *gc, int domid, const char *state_file)
756 {
757     libxl__json_object *args = NULL;
758 
759     libxl__qmp_param_add_string(gc, &args, "filename", state_file);
760 
761     return qmp_run_command(gc, domid, "xen-load-devices-state", args,
762                            NULL, NULL);
763 }
764 
libxl__qmp_resume(libxl__gc * gc,int domid)765 int libxl__qmp_resume(libxl__gc *gc, int domid)
766 {
767     return qmp_run_command(gc, domid, "cont", NULL, NULL, NULL);
768 }
769 
libxl__qmp_nbd_server_start(libxl__gc * gc,int domid,const char * host,const char * port)770 int libxl__qmp_nbd_server_start(libxl__gc *gc, int domid,
771                                 const char *host, const char *port)
772 {
773     libxl__json_object *args = NULL;
774     libxl__json_object *addr = NULL;
775     libxl__json_object *data = NULL;
776 
777     /* 'addr': {
778      *   'type': 'inet',
779      *   'data': {
780      *     'host': '$nbd_host',
781      *     'port': '$nbd_port'
782      *   }
783      * }
784      */
785     libxl__qmp_param_add_string(gc, &data, "host", host);
786     libxl__qmp_param_add_string(gc, &data, "port", port);
787 
788     libxl__qmp_param_add_string(gc, &addr, "type", "inet");
789     qmp_parameters_common_add(gc, &addr, "data", data);
790 
791     qmp_parameters_common_add(gc, &args, "addr", addr);
792 
793     return qmp_run_command(gc, domid, "nbd-server-start", args, NULL, NULL);
794 }
795 
libxl__qmp_nbd_server_add(libxl__gc * gc,int domid,const char * disk)796 int libxl__qmp_nbd_server_add(libxl__gc *gc, int domid, const char *disk)
797 {
798     libxl__json_object *args = NULL;
799 
800     libxl__qmp_param_add_string(gc, &args, "device", disk);
801     libxl__qmp_param_add_bool(gc, &args, "writable", true);
802 
803     return qmp_run_command(gc, domid, "nbd-server-add", args, NULL, NULL);
804 }
805 
libxl__qmp_start_replication(libxl__gc * gc,int domid,bool primary)806 int libxl__qmp_start_replication(libxl__gc *gc, int domid, bool primary)
807 {
808     libxl__json_object *args = NULL;
809 
810     libxl__qmp_param_add_bool(gc, &args, "enable", true);
811     libxl__qmp_param_add_bool(gc, &args, "primary", primary);
812 
813     return qmp_run_command(gc, domid, "xen-set-replication", args, NULL, NULL);
814 }
815 
libxl__qmp_query_xen_replication_status(libxl__gc * gc,int domid)816 int libxl__qmp_query_xen_replication_status(libxl__gc *gc, int domid)
817 {
818     return qmp_run_command(gc, domid, "query-xen-replication-status", NULL,
819                            NULL, NULL);
820 }
821 
libxl__qmp_colo_do_checkpoint(libxl__gc * gc,int domid)822 int libxl__qmp_colo_do_checkpoint(libxl__gc *gc, int domid)
823 {
824     return qmp_run_command(gc, domid, "xen-colo-do-checkpoint",
825                            NULL, NULL, NULL);
826 }
827 
libxl__qmp_stop_replication(libxl__gc * gc,int domid,bool primary)828 int libxl__qmp_stop_replication(libxl__gc *gc, int domid, bool primary)
829 {
830     libxl__json_object *args = NULL;
831 
832     libxl__qmp_param_add_bool(gc, &args, "enable", false);
833     libxl__qmp_param_add_bool(gc, &args, "primary", primary);
834 
835     return qmp_run_command(gc, domid, "xen-set-replication", args, NULL, NULL);
836 }
837 
libxl__qmp_nbd_server_stop(libxl__gc * gc,int domid)838 int libxl__qmp_nbd_server_stop(libxl__gc *gc, int domid)
839 {
840     return qmp_run_command(gc, domid, "nbd-server-stop", NULL, NULL, NULL);
841 }
842 
libxl__qmp_x_blockdev_change(libxl__gc * gc,int domid,const char * parent,const char * child,const char * node)843 int libxl__qmp_x_blockdev_change(libxl__gc *gc, int domid, const char *parent,
844                                  const char *child, const char *node)
845 {
846     libxl__json_object *args = NULL;
847 
848     libxl__qmp_param_add_string(gc, &args, "parent", parent);
849     if (child)
850         libxl__qmp_param_add_string(gc, &args, "child", child);
851     if (node)
852         libxl__qmp_param_add_string(gc, &args, "node", node);
853 
854     return qmp_run_command(gc, domid, "x-blockdev-change", args, NULL, NULL);
855 }
856 
hmp_callback(libxl__qmp_handler * qmp,const libxl__json_object * response,void * opaque)857 static int hmp_callback(libxl__qmp_handler *qmp,
858                         const libxl__json_object *response,
859                         void *opaque)
860 {
861     char **output = opaque;
862     GC_INIT(qmp->ctx);
863     int rc;
864 
865     rc = 0;
866     if (!output)
867         goto out;
868 
869     *output = NULL;
870 
871     if (libxl__json_object_is_string(response)) {
872         *output = libxl__strdup(NOGC, libxl__json_object_get_string(response));
873         goto out;
874     }
875 
876     LOG(ERROR, "Response has unexpected format");
877     rc = ERROR_FAIL;
878 
879 out:
880     GC_FREE;
881     return rc;
882 }
883 
libxl__qmp_hmp(libxl__gc * gc,int domid,const char * command_line,char ** output)884 int libxl__qmp_hmp(libxl__gc *gc, int domid, const char *command_line,
885                    char **output)
886 {
887     libxl__json_object *args = NULL;
888 
889     libxl__qmp_param_add_string(gc, &args, "command-line", command_line);
890 
891     return qmp_run_command(gc, domid, "human-monitor-command", args,
892                            hmp_callback, output);
893 }
894 
895 
896 typedef struct {
897     libxl__ev_qmp qmp;
898     char **output; /* user pointer */
899 } qemu_monitor_command_state;
900 
901 static void qemu_monitor_command_done(libxl__egc *, libxl__ev_qmp *,
902                                       const libxl__json_object *response,
903                                       int rc);
904 
libxl_qemu_monitor_command(libxl_ctx * ctx,uint32_t domid,const char * command_line,char ** output,const libxl_asyncop_how * ao_how)905 int libxl_qemu_monitor_command(libxl_ctx *ctx, uint32_t domid,
906                                const char *command_line, char **output,
907                                const libxl_asyncop_how *ao_how)
908 {
909     AO_CREATE(ctx, domid, ao_how);
910     qemu_monitor_command_state *qmcs;
911     libxl__json_object *args = NULL;
912     int rc;
913 
914     if (!output) {
915         rc = ERROR_INVAL;
916         goto out;
917     }
918 
919     GCNEW(qmcs);
920     libxl__ev_qmp_init(&qmcs->qmp);
921     qmcs->qmp.ao = ao;
922     qmcs->qmp.domid = domid;
923     qmcs->qmp.payload_fd = -1;
924     qmcs->qmp.callback = qemu_monitor_command_done;
925     qmcs->output = output;
926     libxl__qmp_param_add_string(gc, &args, "command-line", command_line);
927     rc = libxl__ev_qmp_send(egc, &qmcs->qmp, "human-monitor-command", args);
928 out:
929     if (rc) return AO_CREATE_FAIL(rc);
930     return AO_INPROGRESS;
931 }
932 
qemu_monitor_command_done(libxl__egc * egc,libxl__ev_qmp * qmp,const libxl__json_object * response,int rc)933 static void qemu_monitor_command_done(libxl__egc *egc, libxl__ev_qmp *qmp,
934                                       const libxl__json_object *response,
935                                       int rc)
936 {
937     STATE_AO_GC(qmp->ao);
938     qemu_monitor_command_state *qmcs = CONTAINER_OF(qmp, *qmcs, qmp);
939 
940     if (rc) goto out;
941 
942     if (!libxl__json_object_is_string(response)) {
943         rc = ERROR_QEMU_API;
944         LOGD(ERROR, qmp->domid, "Response has unexpected format");
945         goto out;
946     }
947 
948     *(qmcs->output) =
949         libxl__strdup(NOGC, libxl__json_object_get_string(response));
950     rc = 0;
951 
952 out:
953     libxl__ev_qmp_dispose(gc, qmp);
954     libxl__ao_complete(egc, ao, rc);
955 }
956 
957 /*
958  * Functions using libxl__ev_qmp
959  */
960 
961 static void dm_stopped(libxl__egc *egc, libxl__ev_qmp *ev,
962                        const libxl__json_object *response, int rc);
963 static void dm_state_fd_ready(libxl__egc *egc, libxl__ev_qmp *ev,
964                               const libxl__json_object *response, int rc);
965 static void dm_state_save_to_fdset(libxl__egc *egc, libxl__ev_qmp *ev, int fdset);
966 static void dm_state_saved(libxl__egc *egc, libxl__ev_qmp *ev,
967                            const libxl__json_object *response, int rc);
968 
969 /* calls dsps->callback_device_model_done when done */
libxl__qmp_suspend_save(libxl__egc * egc,libxl__domain_suspend_state * dsps)970 void libxl__qmp_suspend_save(libxl__egc *egc,
971                              libxl__domain_suspend_state *dsps)
972 {
973     EGC_GC;
974     int rc;
975     libxl__ev_qmp *ev = &dsps->qmp;
976 
977     ev->ao = dsps->ao;
978     ev->domid = dsps->domid;
979     ev->callback = dm_stopped;
980     ev->payload_fd = -1;
981 
982     rc = libxl__ev_qmp_send(egc, ev, "stop", NULL);
983     if (rc)
984         goto error;
985 
986     return;
987 
988 error:
989     dsps->callback_device_model_done(egc, dsps, rc);
990 }
991 
dm_stopped(libxl__egc * egc,libxl__ev_qmp * ev,const libxl__json_object * response,int rc)992 static void dm_stopped(libxl__egc *egc, libxl__ev_qmp *ev,
993                        const libxl__json_object *response, int rc)
994 {
995     EGC_GC;
996     libxl__domain_suspend_state *dsps = CONTAINER_OF(ev, *dsps, qmp);
997     const char *const filename = dsps->dm_savefile;
998     uint32_t dm_domid = libxl_get_stubdom_id(CTX, dsps->domid);
999 
1000     if (rc)
1001         goto error;
1002 
1003     if (dm_domid) {
1004         /* see Linux stubdom interface in docs/stubdom.txt */
1005         dm_state_save_to_fdset(egc, ev, 1);
1006         return;
1007     }
1008 
1009     ev->payload_fd = open(filename, O_WRONLY | O_CREAT, 0600);
1010     if (ev->payload_fd < 0) {
1011         LOGED(ERROR, ev->domid,
1012               "Failed to open file %s for QEMU", filename);
1013         rc = ERROR_FAIL;
1014         goto error;
1015     }
1016 
1017     ev->callback = dm_state_fd_ready;
1018     rc = libxl__ev_qmp_send(egc, ev, "add-fd", NULL);
1019     if (rc)
1020         goto error;
1021 
1022     return;
1023 
1024 error:
1025     if (ev->payload_fd >= 0) {
1026         close(ev->payload_fd);
1027         libxl__remove_file(gc, filename);
1028         ev->payload_fd = -1;
1029     }
1030     dsps->callback_device_model_done(egc, dsps, rc);
1031 }
1032 
dm_state_fd_ready(libxl__egc * egc,libxl__ev_qmp * ev,const libxl__json_object * response,int rc)1033 static void dm_state_fd_ready(libxl__egc *egc, libxl__ev_qmp *ev,
1034                               const libxl__json_object *response, int rc)
1035 {
1036     EGC_GC;
1037     int fdset;
1038     const libxl__json_object *o;
1039     libxl__domain_suspend_state *dsps = CONTAINER_OF(ev, *dsps, qmp);
1040 
1041     close(ev->payload_fd);
1042     ev->payload_fd = -1;
1043 
1044     if (rc)
1045         goto error;
1046 
1047     o = libxl__json_map_get("fdset-id", response, JSON_INTEGER);
1048     if (!o) {
1049         rc = ERROR_QEMU_API;
1050         goto error;
1051     }
1052     fdset = libxl__json_object_get_integer(o);
1053     dm_state_save_to_fdset(egc, ev, fdset);
1054     return;
1055 
1056 error:
1057     assert(rc);
1058     libxl__remove_file(gc, dsps->dm_savefile);
1059     dsps->callback_device_model_done(egc, dsps, rc);
1060 }
1061 
dm_state_save_to_fdset(libxl__egc * egc,libxl__ev_qmp * ev,int fdset)1062 static void dm_state_save_to_fdset(libxl__egc *egc, libxl__ev_qmp *ev, int fdset)
1063 {
1064     EGC_GC;
1065     int rc;
1066     libxl__json_object *args = NULL;
1067     libxl__domain_suspend_state *dsps = CONTAINER_OF(ev, *dsps, qmp);
1068 
1069     ev->callback = dm_state_saved;
1070 
1071     /* The `live` parameter was added to QEMU 2.11. It signals QEMU that
1072      * the save operation is for a live migration rather than for taking a
1073      * snapshot. */
1074     if (qmp_ev_qemu_compare_version(ev, 2, 11, 0) >= 0)
1075         libxl__qmp_param_add_bool(gc, &args, "live", dsps->live);
1076     QMP_PARAMETERS_SPRINTF(&args, "filename", "/dev/fdset/%d", fdset);
1077     rc = libxl__ev_qmp_send(egc, ev, "xen-save-devices-state", args);
1078     if (rc)
1079         goto error;
1080 
1081     return;
1082 
1083 error:
1084     assert(rc);
1085     if (!libxl_get_stubdom_id(CTX, dsps->domid))
1086         libxl__remove_file(gc, dsps->dm_savefile);
1087     dsps->callback_device_model_done(egc, dsps, rc);
1088 }
1089 
dm_state_saved(libxl__egc * egc,libxl__ev_qmp * ev,const libxl__json_object * response,int rc)1090 static void dm_state_saved(libxl__egc *egc, libxl__ev_qmp *ev,
1091                            const libxl__json_object *response, int rc)
1092 {
1093     EGC_GC;
1094     libxl__domain_suspend_state *dsps = CONTAINER_OF(ev, *dsps, qmp);
1095 
1096     if (rc)
1097         libxl__remove_file(gc, dsps->dm_savefile);
1098 
1099     dsps->callback_device_model_done(egc, dsps, rc);
1100 }
1101 
1102 
1103 /* ------------ Implementation of libxl__ev_qmp ---------------- */
1104 
1105 /*
1106  * Possible internal state compared to qmp_state:
1107  *
1108  * qmp_state     External   cfd    efd     id     rx_buf* tx_buf* msg* lock
1109  * disconnected   Idle       NULL   Idle    reset  free    free    free Idle
1110  * waiting_lock   Active     open   Idle    reset  used    free    set  Active
1111  * connecting     Active     open   IN      reset  used    free    set  Acquired
1112  * cap.neg        Active     open   IN|OUT  sent   used    cap_neg set  Acquired
1113  * cap.neg        Active     open   IN      sent   used    free    set  Acquired
1114  * connected      Connected  open   IN      any    used    free    free Acquired
1115  * waiting_reply  Active     open   IN|OUT  sent   used    free    set  Acquired
1116  * waiting_reply  Active     open   IN|OUT  sent   used    user's  free Acquired
1117  * waiting_reply  Active     open   IN      sent   used    free    free Acquired
1118  * broken[1]      none[2]    any    Active  any    any     any     any  any
1119  *
1120  * [1] When an internal function return an error, it can leave ev_qmp in a
1121  * `broken` state but only if the caller is another internal function.
1122  * That `broken` needs to be cleaned up, e.i. transitionned to the
1123  * `disconnected` state, before the control of ev_qmp is released outsides
1124  * of ev_qmp implementation.
1125  *
1126  * [2] This internal state should not be visible externally, see [1].
1127  *
1128  * Possible buffers states:
1129  * - receiving buffer:
1130  *                     free   used
1131  *     rx_buf           NULL   NULL or allocated
1132  *     rx_buf_size      0      allocation size of `rx_buf`
1133  *     rx_buf_used      0      <= rx_buf_size, actual data in the buffer
1134  * - transmitting buffer:
1135  *                     free   used
1136  *     tx_buf           NULL   contains data
1137  *     tx_buf_len       0      size of data
1138  *     tx_buf_off       0      <= tx_buf_len, data already sent
1139  * - queued user command:
1140  *                     free  set
1141  *     msg              NULL  contains data
1142  *     msg_id           0     id assoctiated with the command in `msg`
1143  *
1144  * - Allowed internal state transition:
1145  * disconnected                     -> waiting_lock
1146  * waiting_lock                     -> connecting
1147  * connection                       -> capability_negotiation
1148  * capability_negotiation/connected -> waiting_reply
1149  * waiting_reply                    -> connected
1150  * any                              -> broken
1151  * broken                           -> disconnected
1152  * any                              -> disconnected
1153  *
1154  * The QEMU Machine Protocol (QMP) specification can be found in the QEMU
1155  * repository:
1156  * https://git.qemu.org/?p=qemu.git;a=blob_plain;f=docs/interop/qmp-spec.txt
1157  */
1158 
1159 /* prototypes */
1160 
1161 static void qmp_ev_fd_callback(libxl__egc *egc, libxl__ev_fd *ev_fd,
1162                                int fd, short events, short revents);
1163 static int qmp_ev_callback_writable(libxl__gc *gc,
1164                                     libxl__ev_qmp *ev, int fd);
1165 static int qmp_ev_callback_readable(libxl__egc *egc,
1166                                     libxl__ev_qmp *ev, int fd);
1167 static int qmp_ev_get_next_msg(libxl__egc *egc, libxl__ev_qmp *ev,
1168                                libxl__json_object **o_r);
1169 static int qmp_ev_handle_message(libxl__egc *egc,
1170                                  libxl__ev_qmp *ev,
1171                                  const libxl__json_object *resp);
1172 
1173 /* helpers */
1174 
qmp_ev_ensure_reading_writing(libxl__gc * gc,libxl__ev_qmp * ev)1175 static void qmp_ev_ensure_reading_writing(libxl__gc *gc, libxl__ev_qmp *ev)
1176     /* Update the state of `efd` to match the permited state
1177      * on entry: !disconnected */
1178 {
1179     short events = POLLIN;
1180 
1181     if (ev->state == qmp_state_waiting_lock)
1182         /* We can't modify the efd yet, as it isn't registered. */
1183         return;
1184 
1185     if (ev->tx_buf)
1186         events |= POLLOUT;
1187     else if ((ev->state == qmp_state_waiting_reply) && ev->msg)
1188         events |= POLLOUT;
1189 
1190     libxl__ev_fd_modify(gc, &ev->efd, events);
1191 }
1192 
qmp_ev_set_state(libxl__gc * gc,libxl__ev_qmp * ev,libxl__qmp_state new_state)1193 static void qmp_ev_set_state(libxl__gc *gc, libxl__ev_qmp *ev,
1194                              libxl__qmp_state new_state)
1195     /* on entry: !broken and !disconnected */
1196 {
1197     switch (new_state) {
1198     case qmp_state_disconnected:
1199         break;
1200     case qmp_state_waiting_lock:
1201         assert(ev->state == qmp_state_disconnected);
1202         break;
1203     case qmp_state_connecting:
1204         assert(ev->state == qmp_state_waiting_lock);
1205         break;
1206     case qmp_state_capability_negotiation:
1207         assert(ev->state == qmp_state_connecting);
1208         break;
1209     case qmp_state_waiting_reply:
1210         assert(ev->state == qmp_state_capability_negotiation ||
1211                ev->state == qmp_state_connected);
1212         break;
1213     case qmp_state_connected:
1214         assert(ev->state == qmp_state_waiting_reply);
1215         break;
1216     }
1217 
1218     ev->state = new_state;
1219 
1220     qmp_ev_ensure_reading_writing(gc, ev);
1221 }
1222 
qmp_ev_tx_buf_clear(libxl__ev_qmp * ev)1223 static void qmp_ev_tx_buf_clear(libxl__ev_qmp *ev)
1224 {
1225     ev->tx_buf = NULL;
1226     ev->tx_buf_len = 0;
1227     ev->tx_buf_off = 0;
1228 }
1229 
qmp_error_class_to_libxl_error_code(libxl__gc * gc,const char * eclass)1230 static int qmp_error_class_to_libxl_error_code(libxl__gc *gc,
1231                                                const char *eclass)
1232 {
1233     const libxl_enum_string_table *t = libxl_error_string_table;
1234     const char skip[] = "QMP_";
1235     const size_t skipl = sizeof(skip) - 1;
1236 
1237     /* compare "QMP_GENERIC_ERROR" from libxl_error to "GenericError"
1238      * generated by the QMP server */
1239 
1240     for (; t->s; t++) {
1241             const char *s = eclass;
1242             const char *se = t->s;
1243         if (strncasecmp(t->s, skip, skipl))
1244             continue;
1245         se += skipl;
1246         while (*s && *se) {
1247             /* skip underscores */
1248             if (*se == '_') {
1249                 se++;
1250                 continue;
1251             }
1252             if (tolower(*s) != tolower(*se))
1253                 break;
1254             s++, se++;
1255         }
1256         if (!*s && !*se)
1257             return t->v;
1258     }
1259 
1260     LOG(ERROR, "Unknown QMP error class '%s'", eclass);
1261     return ERROR_UNKNOWN_QMP_ERROR;
1262 }
1263 
1264 /* Setup connection */
1265 
1266 static void qmp_ev_lock_aquired(libxl__egc *, libxl__ev_slowlock *,
1267                                 int rc);
1268 static void lock_error_callback(libxl__egc *, libxl__ev_immediate *);
1269 
qmp_ev_connect(libxl__egc * egc,libxl__ev_qmp * ev)1270 static int qmp_ev_connect(libxl__egc *egc, libxl__ev_qmp *ev)
1271     /* disconnected -> waiting_lock/connecting but with `msg` free
1272      * on error: broken */
1273 {
1274     EGC_GC;
1275     int fd;
1276     int rc;
1277 
1278     /* Convenience aliases */
1279     libxl__ev_slowlock *lock = &ev->lock;
1280 
1281     assert(ev->state == qmp_state_disconnected);
1282 
1283     libxl__carefd_begin();
1284     fd = socket(AF_UNIX, SOCK_STREAM, 0);
1285     ev->cfd = libxl__carefd_opened(CTX, fd);
1286     if (!ev->cfd) {
1287         LOGED(ERROR, ev->domid, "socket() failed");
1288         rc = ERROR_FAIL;
1289         goto out;
1290     }
1291     rc = libxl_fd_set_nonblock(CTX, libxl__carefd_fd(ev->cfd), 1);
1292     if (rc)
1293         goto out;
1294 
1295     qmp_ev_set_state(gc, ev, qmp_state_waiting_lock);
1296 
1297     lock->ao = ev->ao;
1298     lock->domid = ev->domid;
1299     lock->callback = qmp_ev_lock_aquired;
1300     libxl__ev_slowlock_lock(egc, &ev->lock);
1301 
1302     return 0;
1303 
1304 out:
1305     return rc;
1306 }
1307 
qmp_ev_lock_aquired(libxl__egc * egc,libxl__ev_slowlock * lock,int rc)1308 static void qmp_ev_lock_aquired(libxl__egc *egc, libxl__ev_slowlock *lock,
1309                                 int rc)
1310     /* waiting_lock (with `lock' Acquired) -> connecting
1311      * on error: broken */
1312 {
1313     libxl__ev_qmp *ev = CONTAINER_OF(lock, *ev, lock);
1314     EGC_GC;
1315     const char *qmp_socket_path;
1316     struct sockaddr_un un;
1317     int r;
1318 
1319     if (rc) goto out;
1320 
1321     qmp_socket_path = libxl__qemu_qmp_path(gc, ev->domid);
1322 
1323     LOGD(DEBUG, ev->domid, "Connecting to %s", qmp_socket_path);
1324 
1325     rc = libxl__prepare_sockaddr_un(gc, &un, qmp_socket_path,
1326                                     "QMP socket");
1327     if (rc)
1328         goto out;
1329 
1330     r = connect(libxl__carefd_fd(ev->cfd),
1331                 (struct sockaddr *) &un, sizeof(un));
1332     if (r && errno != EINPROGRESS) {
1333         LOGED(ERROR, ev->domid, "Failed to connect to QMP socket %s",
1334               qmp_socket_path);
1335         rc = ERROR_FAIL;
1336         goto out;
1337     }
1338 
1339     rc = libxl__ev_fd_register(gc, &ev->efd, qmp_ev_fd_callback,
1340                                libxl__carefd_fd(ev->cfd), POLLIN);
1341     if (rc)
1342         goto out;
1343 
1344     qmp_ev_set_state(gc, ev, qmp_state_connecting);
1345 
1346     return;
1347 
1348 out:
1349     /* An error occurred and we need to let the caller know.  At this
1350      * point, we can only do so via the callback. Unfortunately, the
1351      * callback of libxl__ev_slowlock_lock() might be called synchronously,
1352      * but libxl__ev_qmp_send() promise that it will not call the callback
1353      * synchronously. So we have to arrange to call the callback
1354      * asynchronously. */
1355     ev->rc = rc;
1356     ev->ei.callback = lock_error_callback;
1357     libxl__ev_immediate_register(egc, &ev->ei);
1358 }
1359 
lock_error_callback(libxl__egc * egc,libxl__ev_immediate * ei)1360 static void lock_error_callback(libxl__egc *egc, libxl__ev_immediate *ei)
1361     /* broken -> disconnected */
1362 {
1363     EGC_GC;
1364     libxl__ev_qmp *ev = CONTAINER_OF(ei, *ev, ei);
1365 
1366     int rc = ev->rc;
1367 
1368     /* On error, deallocate all private resources */
1369     libxl__ev_qmp_dispose(gc, ev);
1370 
1371     /* And tell libxl__ev_qmp user about the error */
1372     ev->callback(egc, ev, NULL, rc); /* must be last */
1373 }
1374 
1375 /* QMP FD callbacks */
1376 
qmp_ev_fd_callback(libxl__egc * egc,libxl__ev_fd * ev_fd,int fd,short events,short revents)1377 static void qmp_ev_fd_callback(libxl__egc *egc, libxl__ev_fd *ev_fd,
1378                                int fd, short events, short revents)
1379     /* On entry, ev_fd is (of course) Active.  The ev_qmp may be in any
1380      * state where this is permitted.  qmp_ev_fd_callback will do the work
1381      * necessary to make progress, depending on the current state, and make
1382      * the appropriate state transitions and callbacks.  */
1383 {
1384     libxl__ev_qmp *ev = CONTAINER_OF(ev_fd, *ev, efd);
1385     STATE_AO_GC(ev->ao);
1386     int rc;
1387 
1388     if (revents & (POLLHUP|POLLERR)) {
1389         int r;
1390         int error_val = 0;
1391         socklen_t opt_len = sizeof(error_val);
1392 
1393         r = getsockopt(fd, SOL_SOCKET, SO_ERROR, &error_val, &opt_len);
1394         if (r)
1395             LOGED(ERROR, ev->domid, "getsockopt failed");
1396         if (!r && error_val) {
1397             errno = error_val;
1398             LOGED(ERROR, ev->domid, "error on QMP socket");
1399         } else {
1400             LOGD(ERROR, ev->domid,
1401                  "received POLLHUP|POLLERR from QMP socket");
1402         }
1403         rc = ERROR_PROTOCOL_ERROR_QMP;
1404         goto error;
1405     }
1406 
1407     if (revents & ~(POLLIN|POLLOUT)) {
1408         LOGD(ERROR, ev->domid,
1409              "unexpected poll event 0x%x on QMP socket (expected POLLIN "
1410              "and/or POLLOUT)",
1411             revents);
1412         rc = ERROR_FAIL;
1413         goto error;
1414     }
1415 
1416     if (revents & POLLOUT) {
1417         rc = qmp_ev_callback_writable(gc, ev, fd);
1418         if (rc)
1419             goto error;
1420     }
1421 
1422     if (revents & POLLIN) {
1423         rc = qmp_ev_callback_readable(egc, ev, fd);
1424         if (rc < 0)
1425             goto error;
1426         if (rc == 1) {
1427             /* user callback has been called */
1428             return;
1429         }
1430     }
1431 
1432     return;
1433 
1434 error:
1435     assert(rc);
1436 
1437     LOGD(ERROR, ev->domid,
1438          "Error happened with the QMP connection to QEMU");
1439 
1440     /* On error, deallocate all private ressources */
1441     libxl__ev_qmp_dispose(gc, ev);
1442 
1443     /* And tell libxl__ev_qmp user about the error */
1444     ev->callback(egc, ev, NULL, rc); /* must be last */
1445 }
1446 
qmp_ev_callback_writable(libxl__gc * gc,libxl__ev_qmp * ev,int fd)1447 static int qmp_ev_callback_writable(libxl__gc *gc,
1448                                     libxl__ev_qmp *ev, int fd)
1449     /* on entry: !disconnected
1450      * on return, one of these state transition:
1451      *   waiting_reply (with msg set) -> waiting_reply (with msg free)
1452      *   tx_buf set -> same state or tx_buf free
1453      * on error: broken */
1454 {
1455     int rc;
1456     ssize_t r;
1457 
1458     if (ev->state == qmp_state_waiting_reply) {
1459         if (ev->msg) {
1460             assert(!ev->tx_buf);
1461             ev->tx_buf = ev->msg;
1462             ev->tx_buf_len = strlen(ev->msg);
1463             ev->tx_buf_off = 0;
1464             ev->id = ev->msg_id;
1465             ev->msg = NULL;
1466             ev->msg_id = 0;
1467         }
1468     }
1469 
1470     assert(ev->tx_buf);
1471 
1472     LOG_QMP("sending: '%.*s'", (int)ev->tx_buf_len, ev->tx_buf);
1473 
1474     /*
1475      * We will send a file descriptor associated with a command on the
1476      * first byte of this command.
1477      */
1478     if (ev->state == qmp_state_waiting_reply &&
1479         ev->payload_fd >= 0 &&
1480         ev->tx_buf_off == 0) {
1481 
1482         rc = libxl__sendmsg_fds(gc, fd, ev->tx_buf[ev->tx_buf_off],
1483                                 1, &ev->payload_fd, "QMP socket");
1484         /* Check for EWOULDBLOCK, and return to try again later */
1485         if (rc == ERROR_NOT_READY)
1486             return 0;
1487         if (rc)
1488             return rc;
1489         ev->tx_buf_off++;
1490     }
1491 
1492     while (ev->tx_buf_off < ev->tx_buf_len) {
1493         ssize_t max_write = ev->tx_buf_len - ev->tx_buf_off;
1494         r = write(fd, ev->tx_buf + ev->tx_buf_off, max_write);
1495         if (r < 0) {
1496             if (errno == EINTR)
1497                 continue;
1498             if (errno == EWOULDBLOCK)
1499                 break;
1500             LOGED(ERROR, ev->domid, "failed to write to QMP socket");
1501             return ERROR_FAIL;
1502         }
1503         assert(r > 0 && r <= max_write);
1504         ev->tx_buf_off += r;
1505     }
1506 
1507     if (ev->tx_buf_off == ev->tx_buf_len)
1508         qmp_ev_tx_buf_clear(ev);
1509 
1510     qmp_ev_ensure_reading_writing(gc, ev);
1511 
1512     return 0;
1513 }
1514 
qmp_ev_callback_readable(libxl__egc * egc,libxl__ev_qmp * ev,int fd)1515 static int qmp_ev_callback_readable(libxl__egc *egc,
1516                                     libxl__ev_qmp *ev, int fd)
1517     /*
1518      * Return values:
1519      *   < 0    libxl error code
1520      *   0      success
1521      *   1      success, but a user callback has been called,
1522      *          `ev` should not be used anymore.
1523      *
1524      * This function will update the rx buffer and possibly update
1525      * ev->state:
1526      *  connecting             -> capability_negotiation
1527      *  capability_negotiation -> waiting_reply
1528      *  waiting_reply          -> connected
1529      * on error: broken
1530      */
1531 {
1532     STATE_AO_GC(ev->ao);
1533     int rc;
1534     ssize_t r;
1535 
1536     while (1) {
1537         while (1) {
1538             libxl__json_object *o = NULL;
1539 
1540             /* parse rx buffer to find one json object */
1541             rc = qmp_ev_get_next_msg(egc, ev, &o);
1542             if (rc == ERROR_NOTFOUND)
1543                 break;
1544             else if (rc)
1545                 return rc;
1546 
1547             /* Must be last and return when the user callback is called */
1548             rc = qmp_ev_handle_message(egc, ev, o);
1549             if (rc)
1550                 /* returns both rc values -ERROR_* and 1 */
1551                 return rc;
1552         }
1553 
1554         /* Check if the buffer still have space, or increase size */
1555         if (ev->rx_buf_size - ev->rx_buf_used < QMP_RECEIVE_BUFFER_SIZE) {
1556             size_t newsize = ev->rx_buf_size * 2 + QMP_RECEIVE_BUFFER_SIZE;
1557 
1558             if (newsize > QMP_MAX_SIZE_RX_BUF) {
1559                 LOGD(ERROR, ev->domid,
1560                      "QMP receive buffer is too big (%zu > %lld)",
1561                      newsize, QMP_MAX_SIZE_RX_BUF);
1562                 return ERROR_BUFFERFULL;
1563             }
1564             ev->rx_buf_size = newsize;
1565             ev->rx_buf = libxl__realloc(gc, ev->rx_buf, ev->rx_buf_size);
1566         }
1567 
1568         r = read(fd, ev->rx_buf + ev->rx_buf_used,
1569                  ev->rx_buf_size - ev->rx_buf_used);
1570         if (r < 0) {
1571             if (errno == EINTR)
1572                 continue;
1573             if (errno == EWOULDBLOCK)
1574                 break;
1575             LOGED(ERROR, ev->domid, "error reading QMP socket");
1576             return ERROR_FAIL;
1577         }
1578 
1579         if (r == 0) {
1580             LOGD(ERROR, ev->domid, "Unexpected EOF on QMP socket");
1581             return ERROR_PROTOCOL_ERROR_QMP;
1582         }
1583 
1584         LOG_QMP("received %ldB: '%.*s'", r,
1585                 (int)r, ev->rx_buf + ev->rx_buf_used);
1586 
1587         ev->rx_buf_used += r;
1588         assert(ev->rx_buf_used <= ev->rx_buf_size);
1589     }
1590 
1591     return 0;
1592 }
1593 
1594 /* Handle messages received from QMP server */
1595 
qmp_ev_get_next_msg(libxl__egc * egc,libxl__ev_qmp * ev,libxl__json_object ** o_r)1596 static int qmp_ev_get_next_msg(libxl__egc *egc, libxl__ev_qmp *ev,
1597                                libxl__json_object **o_r)
1598     /* Find a JSON object and store it in o_r.
1599      * return ERROR_NOTFOUND if no object is found.
1600      *
1601      * !disconnected -> same state (with rx buffer updated)
1602      */
1603 {
1604     STATE_AO_GC(ev->ao);
1605     size_t len;
1606     char *end = NULL;
1607     const char eom[] = "\r\n";
1608     const size_t eoml = sizeof(eom) - 1;
1609     libxl__json_object *o = NULL;
1610 
1611     if (!ev->rx_buf_used)
1612         return ERROR_NOTFOUND;
1613 
1614     /* Search for the end of a QMP message: "\r\n" */
1615     end = memmem(ev->rx_buf, ev->rx_buf_used, eom, eoml);
1616     if (!end)
1617         return ERROR_NOTFOUND;
1618     len = (end - ev->rx_buf) + eoml;
1619 
1620     LOG_QMP("parsing %luB: '%.*s'", len, (int)len, ev->rx_buf);
1621 
1622     /* Replace \r by \0 so that libxl__json_parse can use strlen */
1623     ev->rx_buf[len - eoml] = '\0';
1624     o = libxl__json_parse(gc, ev->rx_buf);
1625 
1626     if (!o) {
1627         LOGD(ERROR, ev->domid, "Parse error");
1628         return ERROR_PROTOCOL_ERROR_QMP;
1629     }
1630 
1631     ev->rx_buf_used -= len;
1632     memmove(ev->rx_buf, ev->rx_buf + len, ev->rx_buf_used);
1633 
1634     LOG_QMP("JSON object received: %s", JSON(o));
1635 
1636     *o_r = o;
1637 
1638     return 0;
1639 }
1640 
1641 static int qmp_ev_parse_error_messages(libxl__egc *egc,
1642                                        libxl__ev_qmp *ev,
1643                                        const libxl__json_object *resp);
1644 
qmp_ev_handle_message(libxl__egc * egc,libxl__ev_qmp * ev,const libxl__json_object * resp)1645 static int qmp_ev_handle_message(libxl__egc *egc,
1646                                  libxl__ev_qmp *ev,
1647                                  const libxl__json_object *resp)
1648     /*
1649      * This function will handle every messages sent by the QMP server.
1650      * Return values:
1651      *   < 0    libxl error code
1652      *   0      success
1653      *   1      success, but a user callback has been called,
1654      *          `ev` should not be used anymore.
1655      *
1656      * Possible state changes:
1657      * connecting -> capability_negotiation
1658      * capability_negotiation -> waiting_reply
1659      * waiting_reply -> waiting_reply/connected
1660      *
1661      * on error: broken
1662      */
1663 {
1664     STATE_AO_GC(ev->ao);
1665     int id;
1666     char *buf;
1667     int rc = 0;
1668     const libxl__json_object *o;
1669     const libxl__json_object *response;
1670     libxl__qmp_message_type type = qmp_response_type(resp);
1671 
1672     switch (type) {
1673     case LIBXL__QMP_MESSAGE_TYPE_QMP:
1674         /* greeting message */
1675 
1676         if (ev->state != qmp_state_connecting) {
1677             LOGD(ERROR, ev->domid,
1678                  "Unexpected greeting message received");
1679             return ERROR_PROTOCOL_ERROR_QMP;
1680         }
1681 
1682         /*
1683          * Store advertised QEMU version
1684          * { "QMP": { "version": {
1685          *     "qemu": { "major": int, "minor": int, "micro": int } } } }
1686          */
1687         o = libxl__json_map_get("QMP", resp, JSON_MAP);
1688         o = libxl__json_map_get("version", o, JSON_MAP);
1689         o = libxl__json_map_get("qemu", o, JSON_MAP);
1690 #define GRAB_VERSION(level) do { \
1691         ev->qemu_version.level = libxl__json_object_get_integer( \
1692             libxl__json_map_get(#level, o, JSON_INTEGER)); \
1693         } while (0)
1694         GRAB_VERSION(major);
1695         GRAB_VERSION(minor);
1696         GRAB_VERSION(micro);
1697 #undef GRAB_VERSION
1698         LOGD(DEBUG, ev->domid, "QEMU version: %d.%d.%d",
1699              ev->qemu_version.major,
1700              ev->qemu_version.minor,
1701              ev->qemu_version.micro);
1702 
1703         /* Prepare next message to send */
1704         assert(!ev->tx_buf);
1705         ev->id = ev->next_id++;
1706         buf = qmp_prepare_cmd(gc, "qmp_capabilities", NULL, ev->id);
1707         if (!buf) {
1708             LOGD(ERROR, ev->domid,
1709                  "Failed to generate qmp_capabilities command");
1710             return ERROR_FAIL;
1711         }
1712         ev->tx_buf = buf;
1713         ev->tx_buf_len = strlen(buf);
1714         ev->tx_buf_off = 0;
1715         qmp_ev_set_state(gc, ev, qmp_state_capability_negotiation);
1716 
1717         return 0;
1718 
1719     case LIBXL__QMP_MESSAGE_TYPE_RETURN:
1720     case LIBXL__QMP_MESSAGE_TYPE_ERROR:
1721         /*
1722          * Reply to a command (success/error) or server error
1723          *
1724          * In this cases, we are parsing two possibles responses:
1725          * - success:
1726          * { "return": json-value, "id": int }
1727          * - error:
1728          * { "error": { "class": string, "desc": string }, "id": int }
1729          */
1730 
1731         o = libxl__json_map_get("id", resp, JSON_INTEGER);
1732         if (!o) {
1733             /*
1734              * If "id" isn't present, an error occur on the server before
1735              * it has read the "id" provided by libxl.
1736              *
1737              * We deliberately squash all errors into
1738              * ERROR_PROTOCOL_ERROR_QMP as qmp_ev_parse_error_messages may
1739              * also return ERROR_QMP_* but those are reserved for errors
1740              * return by the caller's command.
1741              */
1742             qmp_ev_parse_error_messages(egc, ev, resp);
1743             return ERROR_PROTOCOL_ERROR_QMP;
1744         }
1745 
1746         id = libxl__json_object_get_integer(o);
1747 
1748         if (id != ev->id) {
1749             LOGD(ERROR, ev->domid,
1750                  "Message from QEMU with unexpected id %d: %s",
1751                  id, JSON(resp));
1752             return ERROR_PROTOCOL_ERROR_QMP;
1753         }
1754 
1755         switch (ev->state) {
1756         case qmp_state_capability_negotiation:
1757             if (type != LIBXL__QMP_MESSAGE_TYPE_RETURN) {
1758                 LOGD(ERROR, ev->domid,
1759                      "Error during capability negotiation: %s",
1760                      JSON(resp));
1761                 return ERROR_PROTOCOL_ERROR_QMP;
1762             }
1763             qmp_ev_set_state(gc, ev, qmp_state_waiting_reply);
1764             return 0;
1765         case qmp_state_waiting_reply:
1766             if (type == LIBXL__QMP_MESSAGE_TYPE_RETURN) {
1767                 response = libxl__json_map_get("return", resp, JSON_ANY);
1768                 rc = 0;
1769             } else {
1770                 /* error message */
1771                 response = NULL;
1772                 rc = qmp_ev_parse_error_messages(egc, ev, resp);
1773             }
1774             qmp_ev_set_state(gc, ev, qmp_state_connected);
1775             ev->callback(egc, ev, response, rc); /* must be last */
1776             return 1;
1777         default:
1778             LOGD(ERROR, ev->domid, "Unexpected message: %s", JSON(resp));
1779             return ERROR_PROTOCOL_ERROR_QMP;
1780         }
1781         return 0;
1782 
1783     case LIBXL__QMP_MESSAGE_TYPE_EVENT:
1784         /* Events are ignored */
1785         return 0;
1786 
1787     case LIBXL__QMP_MESSAGE_TYPE_INVALID:
1788         LOGD(ERROR, ev->domid, "Unexpected message received: %s",
1789              JSON(resp));
1790         return ERROR_PROTOCOL_ERROR_QMP;
1791 
1792     default:
1793         abort();
1794     }
1795 
1796     return 0;
1797 }
1798 
qmp_ev_parse_error_messages(libxl__egc * egc,libxl__ev_qmp * ev,const libxl__json_object * resp)1799 static int qmp_ev_parse_error_messages(libxl__egc *egc,
1800                                        libxl__ev_qmp *ev,
1801                                        const libxl__json_object *resp)
1802     /* no state change */
1803 {
1804     STATE_AO_GC(ev->ao);
1805     int rc;
1806     const char *s;
1807     const libxl__json_object *o;
1808     const libxl__json_object *err;
1809 
1810     /*
1811      * { "error": { "class": string, "desc": string } }
1812      */
1813 
1814     err = libxl__json_map_get("error", resp, JSON_MAP);
1815 
1816     o = libxl__json_map_get("class", err, JSON_STRING);
1817     if (!o) {
1818         LOGD(ERROR, ev->domid,
1819              "Protocol error: missing 'class' member in error message");
1820         return ERROR_PROTOCOL_ERROR_QMP;
1821     }
1822     s = libxl__json_object_get_string(o);
1823     if (s)
1824         rc = qmp_error_class_to_libxl_error_code(gc, s);
1825     else
1826         rc = ERROR_PROTOCOL_ERROR_QMP;
1827 
1828     o = libxl__json_map_get("desc", err, JSON_STRING);
1829     if (!o) {
1830         LOGD(ERROR, ev->domid,
1831              "Protocol error: missing 'desc' member in error message");
1832         return ERROR_PROTOCOL_ERROR_QMP;
1833     }
1834     s = libxl__json_object_get_string(o);
1835     if (s)
1836         LOGD(ERROR, ev->domid, "%s", s);
1837     else
1838         LOGD(ERROR, ev->domid, "Received unexpected error: %s",
1839              JSON(resp));
1840     return rc;
1841 }
1842 
1843 /*
1844  * libxl__ev_qmp_*
1845  */
1846 
libxl__ev_qmp_init(libxl__ev_qmp * ev)1847 void libxl__ev_qmp_init(libxl__ev_qmp *ev)
1848     /* disconnected -> disconnected */
1849 {
1850     /* Start with an message ID that is obviously generated by libxl
1851      * "xlq\0" */
1852     ev->next_id = 0x786c7100;
1853 
1854     ev->cfd = NULL;
1855     libxl__ev_fd_init(&ev->efd);
1856     ev->state = qmp_state_disconnected;
1857     ev->id = 0;
1858 
1859     ev->rx_buf = NULL;
1860     ev->rx_buf_size = ev->rx_buf_used = 0;
1861     qmp_ev_tx_buf_clear(ev);
1862 
1863     ev->msg = NULL;
1864     ev->msg_id = 0;
1865 
1866     ev->qemu_version.major = -1;
1867     ev->qemu_version.minor = -1;
1868     ev->qemu_version.micro = -1;
1869 
1870     libxl__ev_qmplock_init(&ev->lock);
1871     ev->rc = 0;
1872 }
1873 
libxl__ev_qmp_send(libxl__egc * egc,libxl__ev_qmp * ev,const char * cmd,libxl__json_object * args)1874 int libxl__ev_qmp_send(libxl__egc *egc, libxl__ev_qmp *ev,
1875                        const char *cmd, libxl__json_object *args)
1876     /* disconnected -> waiting_lock/connecting
1877      * connected -> waiting_reply (with msg set)
1878      * on error: disconnected */
1879 {
1880     STATE_AO_GC(ev->ao);
1881     int rc;
1882 
1883     LOGD(DEBUG, ev->domid, " ev %p, cmd '%s'", ev, cmd);
1884 
1885     assert(ev->state == qmp_state_disconnected ||
1886            ev->state == qmp_state_connected);
1887     assert(cmd);
1888 
1889     /* Connect to QEMU if not already connected */
1890     if (ev->state == qmp_state_disconnected) {
1891         rc = qmp_ev_connect(egc, ev);
1892         if (rc)
1893             goto error;
1894     }
1895 
1896     /* Prepare user command */
1897     ev->msg_id = ev->next_id++;
1898     ev->msg = qmp_prepare_cmd(gc, cmd, args, ev->msg_id);
1899     if (!ev->msg) {
1900         LOGD(ERROR, ev->domid, "Failed to generate caller's command %s",
1901              cmd);
1902         rc = ERROR_FAIL;
1903         goto error;
1904     }
1905     if (ev->state == qmp_state_connected) {
1906         qmp_ev_set_state(gc, ev, qmp_state_waiting_reply);
1907     }
1908 
1909     return 0;
1910 
1911 error:
1912     libxl__ev_qmp_dispose(gc, ev);
1913     return rc;
1914 }
1915 
libxl__ev_qmp_dispose(libxl__gc * gc,libxl__ev_qmp * ev)1916 void libxl__ev_qmp_dispose(libxl__gc *gc, libxl__ev_qmp *ev)
1917     /* * -> disconnected */
1918 {
1919     LOGD(DEBUG, ev->domid, " ev %p", ev);
1920 
1921     libxl__ev_fd_deregister(gc, &ev->efd);
1922     libxl__carefd_close(ev->cfd);
1923     libxl__ev_slowlock_dispose(gc, &ev->lock);
1924 
1925     libxl__ev_qmp_init(ev);
1926 }
1927 
1928 /*
1929  * Local variables:
1930  * mode: C
1931  * c-basic-offset: 4
1932  * indent-tabs-mode: nil
1933  * End:
1934  */
1935