/**
 * qemuAgentGuestSync:
 * @mon: Monitor
 *
 * Send guest-sync with unique ID
 * and wait for reply. If we get one, check if
 * received ID is equal to given.
 *
 * Returns: 0 on success,
 *          -1 otherwise
 */
static int
qemuAgentGuestSync(qemuAgentPtr mon)
{
    int ret = -1;
    int send_ret;
    unsigned long long id, id_ret;
    qemuAgentMessage sync_msg;

    memset(&sync_msg, 0, sizeof(sync_msg));

    if (virTimeMillisNow(&id) < 0)
        return -1;

    if (virAsprintf(&sync_msg.txBuffer,
                    "{\"execute\":\"guest-sync\", "
                    "\"arguments\":{\"id\":%llu}}", id) < 0) {
        virReportOOMError();
        return -1;
    }

    sync_msg.txLength = strlen(sync_msg.txBuffer);

    VIR_DEBUG("Sending guest-sync command with ID: %llu", id);

    send_ret = qemuAgentSend(mon, &sync_msg, true);

    VIR_DEBUG("qemuAgentSend returned: %d", send_ret);

    if (send_ret < 0) {
        /* error reported */
        goto cleanup;
    }

    if (!sync_msg.rxObject) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Missing monitor reply object"));
        goto cleanup;
    }

    if (virJSONValueObjectGetNumberUlong(sync_msg.rxObject,
                                         "return", &id_ret) < 0) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                        _("Malformed return value"));
        goto cleanup;
    }

    VIR_DEBUG("Guest returned ID: %llu", id_ret);
    if (id_ret != id) {
        qemuReportError(VIR_ERR_INTERNAL_ERROR,
                        _("Guest agent returned ID: %llu instead of %llu"),
                        id_ret, id);
        goto cleanup;
    }
    ret = 0;

cleanup:
    virJSONValueFree(sync_msg.rxObject);
    VIR_FREE(sync_msg.txBuffer);
    return ret;
}
static int
qemuAgentCommand(qemuAgentPtr mon,
                 virJSONValuePtr cmd,
                 virJSONValuePtr *reply,
                 int seconds)
{
    int ret = -1;
    qemuAgentMessage msg;
    char *cmdstr = NULL;
    int await_event = mon->await_event;

    *reply = NULL;

    if (qemuAgentGuestSync(mon) < 0) {
        /* helper reported the error */
        return -1;
    }

    memset(&msg, 0, sizeof(msg));

    if (!(cmdstr = virJSONValueToString(cmd, false))) {
        virReportOOMError();
        goto cleanup;
    }
    if (virAsprintf(&msg.txBuffer, "%s" LINE_ENDING, cmdstr) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    msg.txLength = strlen(msg.txBuffer);

    VIR_DEBUG("Send command '%s' for write, seconds = %d", cmdstr, seconds);

    ret = qemuAgentSend(mon, &msg, seconds);

    VIR_DEBUG("Receive command reply ret=%d rxObject=%p",
              ret, msg.rxObject);

    if (ret == 0) {
        /* If we haven't obtained any reply but we wait for an
         * event, then don't report this as error */
        if (!msg.rxObject) {
            if (await_event) {
                VIR_DEBUG("Woken up by event %d", await_event);
            } else {
                virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                               _("Missing monitor reply object"));
                ret = -1;
            }
        } else {
            *reply = msg.rxObject;
        }
    }

cleanup:
    VIR_FREE(cmdstr);
    VIR_FREE(msg.txBuffer);

    return ret;
}
static int
qemuAgentCommand(qemuAgentPtr mon,
                 virJSONValuePtr cmd,
                 virJSONValuePtr *reply)
{
    int ret = -1;
    qemuAgentMessage msg;
    char *cmdstr = NULL;

    *reply = NULL;

    if (qemuAgentGuestSync(mon) < 0) {
        /* helper reported the error */
        return -1;
    }

    memset(&msg, 0, sizeof(msg));

    if (!(cmdstr = virJSONValueToString(cmd))) {
        virReportOOMError();
        goto cleanup;
    }
    if (virAsprintf(&msg.txBuffer, "%s" LINE_ENDING, cmdstr) < 0) {
        virReportOOMError();
        goto cleanup;
    }
    msg.txLength = strlen(msg.txBuffer);

    VIR_DEBUG("Send command '%s' for write", cmdstr);

    ret = qemuAgentSend(mon, &msg, false);

    VIR_DEBUG("Receive command reply ret=%d rxObject=%p",
              ret, msg.rxObject);

    if (ret == 0) {
        if (!msg.rxObject) {
            qemuReportError(VIR_ERR_INTERNAL_ERROR, "%s",
                            _("Missing monitor reply object"));
            ret = -1;
        } else {
            *reply = msg.rxObject;
        }
    }

cleanup:
    VIR_FREE(cmdstr);
    VIR_FREE(msg.txBuffer);

    return ret;
}