[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]

[Xen-devel] Re: [PATCH V7 7/7] libxl, Introduce a QMP client



On Thu, 21 Jul 2011, Ian Campbell wrote:

> On Wed, 2011-07-20 at 22:24 +0100, Anthony PERARD wrote:
> > QMP stands for QEMU Monitor Protocol and it is used to query information
> > from QEMU or to control QEMU.
> >
> > This implementation will ask QEMU the list of chardevice and store the
> > path to serial0 in xenstored. So we will be able to use xl console with
> > QEMU upstream.
> >
> > In order to connect to the QMP server, a socket file is created in
> > /var/run/xen/qmp-$(domid).
>
> That path doesn't match the implementation now.
>
> Again I think I've reviewed much of this before so I only skimmed it,
> although I paid attention to the new stuff relating to pulling through
> to crlf etc.
>
> > diff --git a/tools/libxl/libxl_qmp.c b/tools/libxl/libxl_qmp.c
> > new file mode 100644
> > index 0000000..90dba72
> > --- /dev/null
> > +++ b/tools/libxl/libxl_qmp.c
> [...]
> > +static int register_serials_chardev_callback(libxl__qmp_handler *qmp,
> > +                                             const libxl__json_object *o)
> > +{
> > +    const libxl__json_object *obj = NULL;
> > +    const libxl__json_object *label = NULL;
> > +    const char *s = NULL;
> > +    flexarray_t *array = NULL;
> > +    int index = 0;
> > +    const char *chardev = NULL;
> > +    int ret = 0;
> > +
> > +    if ((array = json_object_get_array(o)) == NULL) {
> > +        return -1;
> > +    }
> > +
> > +    for (index = 0; index < array->count; index++) {
> > +        if (flexarray_get(array, index, (void**)&obj) != 0)
> > +            break;
>
> I think a helper function to retrieve an index into a json_array would
> be helpful. I think in general exposing the internal use of flexarrays
> in this interface to callers can be avoided.

Ok, I will do this helper.

> > +        label = json_object_get("label", obj, JSON_STRING);
> > +        s = json_object_get_string(label);
>
> If obj is not a map label will be null but json_object_get_string will
> DTRT and return NULL so this works. But perhaps an explicit type check
> would be correct here?

Ok, I will add this explicit check.

> > +/*
> > + * Helpers
> > + */
> > +
> > +static libxl__qmp_message_type qmp_response_type(libxl__qmp_handler *qmp,
> > +                                                 const libxl__json_object 
> > *o)
> > +{
> > +    flexarray_t *maps = json_object_get_map(o);
> > +    libxl__qmp_message_type type;
> > +
> > +    if (maps) {
> > +        libxl__json_map_node *node = NULL;
> > +        int index = 0;
> > +
> > +        for (index = 0; index < maps->count; index++) {
> > +            if (flexarray_get(maps, index, (void**)&node) != 0)
> > +                break;
>
> Another helper function to get the a node from a map? Or even a
> json_map_for_each_node type construct?
>
> > +            if (libxl__qmp_message_type_from_string(node->map_key, &type) 
> > == 0)
> > +                return type;
> > +        }
> > +    }
> > +
> > +    return LIBXL__QMP_MESSAGE_TYPE_INVALID;
> > +}
> > +
> > +static callback_id_pair *qmp_get_callback_from_id(libxl__qmp_handler *qmp,
> > +                                                  const libxl__json_object 
> > *o)
> > +{
> > +    const libxl__json_object *id_object = json_object_get("id", o,
> > +                                                          JSON_INTEGER);
> > +    int id = -1;
> > +    callback_id_pair *pp = NULL;
> > +
> > +    if (id_object) {
> > +        id = json_object_get_integer(id_object);
>
> Check that it is an integer? Presumably the -1 error return is never a
> valid id but it'd save a useless list walk.

Actually, the parametter JSON_INTEGER given to json_object_get ask to
explicitly return a json_object with an integer, otherwise, the function
return null.

So the get_integer will not return an error.

> > +        SIMPLEQ_FOREACH(pp, &qmp->callback_list, next) {
> > +            if (pp->id == id) {
> > +                return pp;
> > +            }
> > +        }
> > +    }
> > +    return NULL;
> > +}
> > +
> [...]
> > +static inline yajl_gen_status libxl__yajl_gen_asciiz(yajl_gen hand,
> > +                                                     const char *str)
> > +{
> > +    return yajl_gen_string(hand, (const unsigned char *)str, strlen(str));
> > +}
>
> Belongs in libxl_json I think.

Actually, I have put it here to not expose the yajl_gen.h to all user of
libxl_internal.h.

Otherwise, yes, it does not really belong to libxl_qmp.

> > +static int qmp_next(libxl__gc *gc, libxl__qmp_handler *qmp)
> > +{
> > +    ssize_t rd;
> > +    char *s = NULL;
> > +    char *s_end = NULL;
> > +
> > +    char *incomplete = NULL;
> > +    size_t incomplete_size = 0;
> > +
> > +    do {
> > +        fd_set rfds;
> > +        int ret = 0;
> > +        struct timeval timeout = {
> > +            .tv_sec = qmp->timeout,
> > +            .tv_usec = 0,
> > +        };
> > +
> > +        FD_ZERO(&rfds);
> > +        FD_SET(qmp->qmp_fd, &rfds);
> > +
> > +        ret = select(qmp->qmp_fd + 1, &rfds, NULL, NULL, &timeout);
> > +        if (ret > 0) {
> > +            rd = read(qmp->qmp_fd, qmp->buffer, QMP_RECEIVE_BUFFER_SIZE);
>
> If you do "if (rd == 0) continue" and the rd < 0 error handling+return
> here the error handling is nearer the error-site and hence easier to
> grok. (also you save a level of indentation, although the inner loop
> isn't wrapping in this particular case)
>
> Actually the error handling for ret = select is much the same, if you
> pull the ret==0 and ret<0 cases up after the select it easier to follow.

OK.

> > +            if (rd > 0) {
> > +                DEBUG_REPORT_RECEIVED(qmp->buffer, rd);
> > +
> > +                do {
> > +                    char *end = NULL;
> > +                    if (incomplete) {
> > +                        size_t current_pos = s - incomplete;
> > +                        incomplete_size += rd;
> > +                        incomplete = libxl__realloc(gc, incomplete, 
> > incomplete_size + 1);
> > +                        incomplete = strncat(incomplete, qmp->buffer, rd);
> > +                        s = incomplete + current_pos;
> > +                        s_end = incomplete + incomplete_size;
> > +                    } else {
> > +                        incomplete = libxl__strndup(gc, qmp->buffer, rd);
> > +                        incomplete_size = rd;
> > +                        s = incomplete;
> > +                        s_end = s + rd;
> > +                    }
> > +
> > +                    end = strstr(s, "\r\n");
>
> Is s definitely NULL terminated here? (yes, according to strncat(3),
> good!)

Exactly :), otherwise a strnstr would be helpfull. (I actually write one
before to use strncat.)

> > +                    if (end) {
> > +                        libxl__json_object *o = NULL;
> > +
> > +                        *end = '\0';
> > +
> > +                        o = libxl__json_parse(gc, s);
> > +                        s = end + 2;
> > +
> > +                        if (o) {
> > +                            qmp_handle_response(qmp, o);
> > +                            json_object_free(qmp->ctx, o);
> > +                        }
>
> "if (!o)" is now an error since you pulled up to a "\r\n"?

Indeed, I should add a log_error, even if libxl__json_parse already
print something. But I'm not sure if return -1 immediatly is a good
idee, maybe the next json object is good.

> > +                    } else {
> > +                        break;
> > +                    }
> > +                } while (s < s_end);
> > +            } else if (rd < 0) {
> > +                LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR,
> > +                                 "Socket read error");
> > +                return rd;
> > +            }
> > +        } else if (ret == 0) {
> > +            LIBXL__LOG(qmp->ctx, LIBXL__LOG_ERROR, "timeout");
> > +            return -1;
> > +        } else if (ret < 0) {
> > +            LIBXL__LOG_ERRNO(qmp->ctx, LIBXL__LOG_ERROR, "Select error");
> > +            return -1;
> > +        }
> > +    } while (s < s_end);
> > +
> > +    return 1;
> > +}
> > +
> [...]
>
> Ian.
>
>

-- 
Anthony PERARD

_______________________________________________
Xen-devel mailing list
Xen-devel@xxxxxxxxxxxxxxxxxxx
http://lists.xensource.com/xen-devel


 


Rackspace

Lists.xenproject.org is hosted with RackSpace, monitoring our
servers 24x7x365 and backed by RackSpace's Fanatical Support®.