2012-08-20 13:06:21 +00:00
|
|
|
/*
|
2013-01-31 01:50:09 +00:00
|
|
|
* Copyright (C) 2011-2013 Red Hat, Inc.
|
2012-08-20 13:06:21 +00:00
|
|
|
*
|
|
|
|
* This library is free software; you can redistribute it and/or
|
|
|
|
* modify it under the terms of the GNU Lesser General Public
|
|
|
|
* License as published by the Free Software Foundation; either
|
|
|
|
* version 2.1 of the License, or (at your option) any later version.
|
|
|
|
*
|
|
|
|
* This library is distributed in the hope that it will be useful,
|
|
|
|
* but WITHOUT ANY WARRANTY; without even the implied warranty of
|
|
|
|
* MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
|
|
|
* Lesser General Public License for more details.
|
|
|
|
*
|
|
|
|
* You should have received a copy of the GNU Lesser General Public
|
2012-09-20 22:30:55 +00:00
|
|
|
* License along with this library. If not, see
|
2012-08-20 13:06:21 +00:00
|
|
|
* <http://www.gnu.org/licenses/>.
|
|
|
|
*
|
|
|
|
*/
|
|
|
|
|
|
|
|
#include <config.h>
|
|
|
|
|
|
|
|
#include <stdio.h>
|
|
|
|
#include <stdlib.h>
|
|
|
|
#include <string.h>
|
|
|
|
#include <time.h>
|
|
|
|
|
|
|
|
#include "qemumonitortestutils.h"
|
|
|
|
|
2012-12-13 15:49:48 +00:00
|
|
|
#include "virthread.h"
|
2012-08-20 13:06:21 +00:00
|
|
|
#include "qemu/qemu_monitor.h"
|
|
|
|
#include "rpc/virnetsocket.h"
|
2012-12-12 18:06:53 +00:00
|
|
|
#include "viralloc.h"
|
2012-12-12 17:59:27 +00:00
|
|
|
#include "virlog.h"
|
2012-12-13 18:21:53 +00:00
|
|
|
#include "virerror.h"
|
2013-04-03 10:36:23 +00:00
|
|
|
#include "virstring.h"
|
2012-08-20 13:06:21 +00:00
|
|
|
|
|
|
|
#define VIR_FROM_THIS VIR_FROM_NONE
|
|
|
|
|
|
|
|
struct _qemuMonitorTestItem {
|
2013-07-25 09:48:11 +00:00
|
|
|
qemuMonitorTestResponseCallback cb;
|
|
|
|
void *opaque;
|
|
|
|
virFreeCallback freecb;
|
2012-08-20 13:06:21 +00:00
|
|
|
};
|
|
|
|
|
|
|
|
struct _qemuMonitorTest {
|
|
|
|
virMutex lock;
|
|
|
|
virThread thread;
|
|
|
|
|
|
|
|
bool json;
|
|
|
|
bool quit;
|
|
|
|
bool running;
|
|
|
|
|
|
|
|
char *incoming;
|
|
|
|
size_t incomingLength;
|
|
|
|
size_t incomingCapacity;
|
|
|
|
|
|
|
|
char *outgoing;
|
|
|
|
size_t outgoingLength;
|
|
|
|
size_t outgoingCapacity;
|
|
|
|
|
|
|
|
virNetSocketPtr server;
|
|
|
|
virNetSocketPtr client;
|
|
|
|
|
|
|
|
qemuMonitorPtr mon;
|
|
|
|
|
2012-11-12 14:33:55 +00:00
|
|
|
char *tmpdir;
|
|
|
|
|
2012-08-20 13:06:21 +00:00
|
|
|
size_t nitems;
|
|
|
|
qemuMonitorTestItemPtr *items;
|
|
|
|
|
|
|
|
virDomainObjPtr vm;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
2013-07-25 09:48:11 +00:00
|
|
|
static void
|
|
|
|
qemuMonitorTestItemFree(qemuMonitorTestItemPtr item)
|
|
|
|
{
|
|
|
|
if (!item)
|
|
|
|
return;
|
|
|
|
|
|
|
|
if (item->freecb)
|
|
|
|
(item->freecb)(item->opaque);
|
|
|
|
|
|
|
|
VIR_FREE(item);
|
|
|
|
}
|
2012-08-20 13:06:21 +00:00
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
|
2012-08-20 13:06:21 +00:00
|
|
|
/*
|
2013-04-19 20:18:14 +00:00
|
|
|
* Appends data for a reply to the outgoing buffer
|
2012-08-20 13:06:21 +00:00
|
|
|
*/
|
2013-07-25 09:48:11 +00:00
|
|
|
int
|
2013-07-18 14:17:31 +00:00
|
|
|
qemuMonitorTestAddReponse(qemuMonitorTestPtr test,
|
|
|
|
const char *response)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
size_t want = strlen(response) + 2;
|
|
|
|
size_t have = test->outgoingCapacity - test->outgoingLength;
|
|
|
|
|
|
|
|
if (have < want) {
|
|
|
|
size_t need = want - have;
|
2013-07-04 10:20:21 +00:00
|
|
|
if (VIR_EXPAND_N(test->outgoing, test->outgoingCapacity, need) < 0)
|
2012-08-20 13:06:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
want -= 2;
|
2013-07-25 09:02:00 +00:00
|
|
|
memcpy(test->outgoing + test->outgoingLength, response, want);
|
|
|
|
memcpy(test->outgoing + test->outgoingLength + want, "\r\n", 2);
|
2012-08-20 13:06:21 +00:00
|
|
|
test->outgoingLength += want + 2;
|
|
|
|
return 0;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
static int
|
2013-07-25 09:48:11 +00:00
|
|
|
qemuMonitorTestAddUnexpectedErrorResponse(qemuMonitorTestPtr test)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
2013-07-25 09:48:11 +00:00
|
|
|
if (test->json) {
|
|
|
|
return qemuMonitorTestAddReponse(test,
|
|
|
|
"{ \"error\": "
|
|
|
|
" { \"desc\": \"Unexpected command\", "
|
|
|
|
" \"class\": \"UnexpectedCommand\" } }");
|
2012-08-20 13:06:21 +00:00
|
|
|
} else {
|
2013-07-25 09:48:11 +00:00
|
|
|
return qemuMonitorTestAddReponse(test, "unexpected command");
|
2012-08-20 13:06:21 +00:00
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
static int
|
2013-07-25 09:48:11 +00:00
|
|
|
qemuMonitorTestProcessCommand(qemuMonitorTestPtr test,
|
|
|
|
const char *cmdstr)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
2013-07-25 09:48:11 +00:00
|
|
|
int ret;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
2013-07-25 09:48:11 +00:00
|
|
|
if (test->nitems == 0) {
|
|
|
|
return qemuMonitorTestAddUnexpectedErrorResponse(test);
|
2012-08-20 13:06:21 +00:00
|
|
|
} else {
|
2013-07-25 09:48:11 +00:00
|
|
|
qemuMonitorTestItemPtr item = test->items[0];
|
|
|
|
ret = (item->cb)(test, item, cmdstr);
|
|
|
|
qemuMonitorTestItemFree(item);
|
|
|
|
if (VIR_DELETE_ELEMENT(test->items, 0, test->nitems) < 0)
|
|
|
|
return -1;
|
2012-08-20 13:06:21 +00:00
|
|
|
}
|
|
|
|
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
|
2012-08-20 13:06:21 +00:00
|
|
|
/*
|
|
|
|
* Handles read/write of monitor data on the monitor server side
|
|
|
|
*/
|
2013-07-18 14:17:31 +00:00
|
|
|
static void
|
|
|
|
qemuMonitorTestIO(virNetSocketPtr sock,
|
|
|
|
int events,
|
|
|
|
void *opaque)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
qemuMonitorTestPtr test = opaque;
|
|
|
|
bool err = false;
|
|
|
|
|
|
|
|
virMutexLock(&test->lock);
|
2013-02-22 21:56:21 +00:00
|
|
|
if (test->quit) {
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
return;
|
|
|
|
}
|
2012-08-20 13:06:21 +00:00
|
|
|
if (events & VIR_EVENT_HANDLE_WRITABLE) {
|
|
|
|
ssize_t ret;
|
|
|
|
if ((ret = virNetSocketWrite(sock,
|
|
|
|
test->outgoing,
|
|
|
|
test->outgoingLength)) < 0) {
|
|
|
|
err = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
memmove(test->outgoing,
|
|
|
|
test->outgoing + ret,
|
|
|
|
test->outgoingLength - ret);
|
|
|
|
test->outgoingLength -= ret;
|
|
|
|
|
|
|
|
if ((test->outgoingCapacity - test->outgoingLength) > 1024)
|
|
|
|
VIR_SHRINK_N(test->outgoing, test->outgoingCapacity, 1024);
|
|
|
|
}
|
|
|
|
|
|
|
|
if (events & VIR_EVENT_HANDLE_READABLE) {
|
|
|
|
ssize_t ret, used;
|
|
|
|
char *t1, *t2;
|
|
|
|
|
|
|
|
if ((test->incomingCapacity - test->incomingLength) < 1024) {
|
|
|
|
if (VIR_EXPAND_N(test->incoming, test->incomingCapacity, 1024) < 0) {
|
|
|
|
err = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if ((ret = virNetSocketRead(sock,
|
|
|
|
test->incoming + test->incomingLength,
|
|
|
|
(test->incomingCapacity - test->incomingLength) - 1)) < 0) {
|
|
|
|
err = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
test->incomingLength += ret;
|
|
|
|
test->incoming[test->incomingLength] = '\0';
|
|
|
|
|
|
|
|
/* Look to see if we've got a complete line, and
|
|
|
|
* if so, handle that command
|
|
|
|
*/
|
|
|
|
t1 = test->incoming;
|
|
|
|
while ((t2 = strstr(t1, "\r\n"))) {
|
|
|
|
*t2 = '\0';
|
|
|
|
|
|
|
|
if (qemuMonitorTestProcessCommand(test, t1) < 0) {
|
|
|
|
err = true;
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
|
|
|
|
t1 = t2 + 2;
|
|
|
|
}
|
|
|
|
used = t1 - test->incoming;
|
|
|
|
memmove(test->incoming, t1, test->incomingLength - used);
|
|
|
|
test->incomingLength -= used;
|
|
|
|
if ((test->incomingCapacity - test->incomingLength) > 1024) {
|
|
|
|
VIR_SHRINK_N(test->incoming,
|
|
|
|
test->incomingCapacity,
|
|
|
|
1024);
|
|
|
|
}
|
|
|
|
}
|
|
|
|
|
|
|
|
if (events & (VIR_EVENT_HANDLE_HANGUP |
|
|
|
|
VIR_EVENT_HANDLE_ERROR))
|
|
|
|
err = true;
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
if (err) {
|
|
|
|
virNetSocketRemoveIOCallback(sock);
|
|
|
|
virNetSocketClose(sock);
|
|
|
|
virObjectUnref(test->client);
|
|
|
|
test->client = NULL;
|
|
|
|
} else {
|
|
|
|
events = VIR_EVENT_HANDLE_READABLE;
|
|
|
|
|
|
|
|
if (test->outgoingLength)
|
|
|
|
events |= VIR_EVENT_HANDLE_WRITABLE;
|
|
|
|
|
|
|
|
virNetSocketUpdateIOCallback(sock, events);
|
|
|
|
}
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
static void
|
|
|
|
qemuMonitorTestWorker(void *opaque)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
qemuMonitorTestPtr test = opaque;
|
|
|
|
|
|
|
|
virMutexLock(&test->lock);
|
|
|
|
|
|
|
|
while (!test->quit) {
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
|
|
|
|
if (virEventRunDefaultImpl() < 0) {
|
2013-02-04 18:31:46 +00:00
|
|
|
virMutexLock(&test->lock);
|
2012-08-20 13:06:21 +00:00
|
|
|
test->quit = true;
|
|
|
|
break;
|
|
|
|
}
|
|
|
|
|
|
|
|
virMutexLock(&test->lock);
|
|
|
|
}
|
|
|
|
|
|
|
|
test->running = false;
|
|
|
|
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
return;
|
|
|
|
}
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
|
2012-11-12 10:34:41 +00:00
|
|
|
static void
|
2013-07-18 14:17:31 +00:00
|
|
|
qemuMonitorTestFreeTimer(int timer ATTRIBUTE_UNUSED,
|
|
|
|
void *opaque ATTRIBUTE_UNUSED)
|
2012-11-12 10:34:41 +00:00
|
|
|
{
|
|
|
|
/* nothing to be done here */
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
void
|
|
|
|
qemuMonitorTestFree(qemuMonitorTestPtr test)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
size_t i;
|
2012-11-12 10:34:41 +00:00
|
|
|
int timer = -1;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
|
|
|
if (!test)
|
|
|
|
return;
|
|
|
|
|
|
|
|
virMutexLock(&test->lock);
|
|
|
|
if (test->running) {
|
|
|
|
test->quit = true;
|
2012-11-12 10:34:41 +00:00
|
|
|
/* HACK: Add a dummy timeout to break event loop */
|
|
|
|
timer = virEventAddTimeout(0, qemuMonitorTestFreeTimer, NULL, NULL);
|
2012-08-20 13:06:21 +00:00
|
|
|
}
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
|
|
|
|
if (test->client) {
|
|
|
|
virNetSocketRemoveIOCallback(test->client);
|
|
|
|
virNetSocketClose(test->client);
|
|
|
|
virObjectUnref(test->client);
|
|
|
|
}
|
|
|
|
|
|
|
|
virObjectUnref(test->server);
|
|
|
|
if (test->mon) {
|
2013-01-09 21:00:32 +00:00
|
|
|
virObjectUnlock(test->mon);
|
2012-08-20 13:06:21 +00:00
|
|
|
qemuMonitorClose(test->mon);
|
|
|
|
}
|
|
|
|
|
|
|
|
virObjectUnref(test->vm);
|
|
|
|
|
2013-07-22 14:57:08 +00:00
|
|
|
if (test->running)
|
|
|
|
virThreadJoin(&test->thread);
|
2012-08-20 13:06:21 +00:00
|
|
|
|
2012-11-12 10:34:41 +00:00
|
|
|
if (timer != -1)
|
|
|
|
virEventRemoveTimeout(timer);
|
|
|
|
|
2013-02-04 18:31:46 +00:00
|
|
|
VIR_FREE(test->incoming);
|
|
|
|
VIR_FREE(test->outgoing);
|
|
|
|
|
2013-05-21 07:53:48 +00:00
|
|
|
for (i = 0; i < test->nitems; i++)
|
2012-08-20 13:06:21 +00:00
|
|
|
qemuMonitorTestItemFree(test->items[i]);
|
|
|
|
VIR_FREE(test->items);
|
|
|
|
|
2012-11-12 14:33:55 +00:00
|
|
|
if (test->tmpdir && rmdir(test->tmpdir) < 0)
|
|
|
|
VIR_WARN("Failed to remove tempdir: %s", strerror(errno));
|
|
|
|
|
|
|
|
VIR_FREE(test->tmpdir);
|
|
|
|
|
2012-08-20 13:06:21 +00:00
|
|
|
virMutexDestroy(&test->lock);
|
|
|
|
VIR_FREE(test);
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
2013-07-25 09:48:11 +00:00
|
|
|
qemuMonitorTestAddHandler(qemuMonitorTestPtr test,
|
|
|
|
qemuMonitorTestResponseCallback cb,
|
|
|
|
void *opaque,
|
|
|
|
virFreeCallback freecb)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
qemuMonitorTestItemPtr item;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(item) < 0)
|
2013-07-04 10:20:21 +00:00
|
|
|
goto error;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
2013-07-25 09:48:11 +00:00
|
|
|
item->cb = cb;
|
|
|
|
item->freecb = freecb;
|
|
|
|
item->opaque = opaque;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
|
|
|
virMutexLock(&test->lock);
|
2013-07-18 15:09:41 +00:00
|
|
|
if (VIR_APPEND_ELEMENT(test->items, test->nitems, item) < 0) {
|
2012-08-20 13:06:21 +00:00
|
|
|
virMutexUnlock(&test->lock);
|
2013-07-04 10:20:21 +00:00
|
|
|
goto error;
|
2012-08-20 13:06:21 +00:00
|
|
|
}
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
|
|
|
|
return 0;
|
|
|
|
|
2013-05-03 12:52:21 +00:00
|
|
|
error:
|
2013-07-25 09:48:11 +00:00
|
|
|
if (freecb)
|
|
|
|
(freecb)(opaque);
|
|
|
|
VIR_FREE(item);
|
2012-08-20 13:06:21 +00:00
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
2013-07-25 09:48:11 +00:00
|
|
|
void *
|
|
|
|
qemuMonitorTestItemGetPrivateData(qemuMonitorTestItemPtr item)
|
|
|
|
{
|
|
|
|
return item ? item->opaque : NULL;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
struct qemuMonitorTestDefaultHandlerData {
|
|
|
|
const char *command_name;
|
|
|
|
const char *response;
|
|
|
|
};
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuMonitorTestProcessCommandDefault(qemuMonitorTestPtr test,
|
|
|
|
qemuMonitorTestItemPtr item,
|
|
|
|
const char *cmdstr)
|
|
|
|
{
|
|
|
|
struct qemuMonitorTestDefaultHandlerData *data = item->opaque;
|
|
|
|
virJSONValuePtr val = NULL;
|
|
|
|
char *cmdcopy = NULL;
|
|
|
|
const char *cmdname;
|
|
|
|
char *tmp;
|
|
|
|
int ret = -1;
|
|
|
|
|
|
|
|
if (test->json) {
|
|
|
|
if (!(val = virJSONValueFromString(cmdstr)))
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
if (!(cmdname = virJSONValueObjectGetString(val, "execute"))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Missing command name in %s", cmdstr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
} else {
|
|
|
|
if (VIR_STRDUP(cmdcopy, cmdstr) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
cmdname = cmdcopy;
|
|
|
|
|
|
|
|
if (!(tmp = strchr(cmdcopy, ' '))) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR,
|
|
|
|
"Cannot find command name in '%s'", cmdstr);
|
|
|
|
goto cleanup;
|
|
|
|
}
|
|
|
|
*tmp = '\0';
|
|
|
|
}
|
|
|
|
|
|
|
|
if (STRNEQ(data->command_name, cmdname))
|
|
|
|
ret = qemuMonitorTestAddUnexpectedErrorResponse(test);
|
|
|
|
else
|
|
|
|
ret = qemuMonitorTestAddReponse(test, data->response);
|
|
|
|
|
|
|
|
cleanup:
|
|
|
|
VIR_FREE(cmdcopy);
|
|
|
|
virJSONValueFree(val);
|
|
|
|
return ret;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
int
|
|
|
|
qemuMonitorTestAddItem(qemuMonitorTestPtr test,
|
|
|
|
const char *command_name,
|
|
|
|
const char *response)
|
|
|
|
{
|
|
|
|
struct qemuMonitorTestDefaultHandlerData *data;
|
|
|
|
|
|
|
|
if (VIR_ALLOC(data) < 0)
|
|
|
|
return -1;
|
|
|
|
|
|
|
|
data->command_name = command_name;
|
|
|
|
data->response = response;
|
|
|
|
|
|
|
|
return qemuMonitorTestAddHandler(test,
|
|
|
|
qemuMonitorTestProcessCommandDefault,
|
|
|
|
data,
|
|
|
|
free);
|
|
|
|
}
|
|
|
|
|
2012-08-20 13:06:21 +00:00
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
static void
|
|
|
|
qemuMonitorTestEOFNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|
|
|
virDomainObjPtr vm ATTRIBUTE_UNUSED)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
|
|
|
|
static void
|
|
|
|
qemuMonitorTestErrorNotify(qemuMonitorPtr mon ATTRIBUTE_UNUSED,
|
|
|
|
virDomainObjPtr vm ATTRIBUTE_UNUSED)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
}
|
|
|
|
|
|
|
|
|
2013-07-25 09:48:11 +00:00
|
|
|
static qemuMonitorCallbacks qemuMonitorTestCallbacks = {
|
2012-08-20 13:06:21 +00:00
|
|
|
.eofNotify = qemuMonitorTestEOFNotify,
|
|
|
|
.errorNotify = qemuMonitorTestErrorNotify,
|
|
|
|
};
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
|
2013-07-22 14:59:22 +00:00
|
|
|
static qemuMonitorTestPtr
|
|
|
|
qemuMonitorCommonTestNew(virDomainXMLOptionPtr xmlopt,
|
|
|
|
virDomainChrSourceDefPtr src)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
2012-10-29 08:28:15 +00:00
|
|
|
qemuMonitorTestPtr test = NULL;
|
2012-11-12 14:33:55 +00:00
|
|
|
char *path = NULL;
|
|
|
|
char *tmpdir_template = NULL;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
2012-11-12 14:33:55 +00:00
|
|
|
if (VIR_ALLOC(test) < 0)
|
2013-07-04 10:20:21 +00:00
|
|
|
goto error;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
|
|
|
if (virMutexInit(&test->lock) < 0) {
|
|
|
|
virReportError(VIR_ERR_INTERNAL_ERROR, "%s",
|
|
|
|
"Cannot initialize mutex");
|
|
|
|
VIR_FREE(test);
|
|
|
|
return NULL;
|
|
|
|
}
|
|
|
|
|
2013-05-03 12:52:21 +00:00
|
|
|
if (VIR_STRDUP(tmpdir_template, "/tmp/libvirt_XXXXXX") < 0)
|
|
|
|
goto error;
|
2012-11-12 14:33:55 +00:00
|
|
|
|
|
|
|
if (!(test->tmpdir = mkdtemp(tmpdir_template))) {
|
|
|
|
virReportSystemError(errno, "%s",
|
|
|
|
"Failed to create temporary directory");
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
|
|
|
|
tmpdir_template = NULL;
|
|
|
|
|
|
|
|
if (virAsprintf(&path, "%s/qemumonitorjsontest.sock", test->tmpdir) < 0)
|
2013-07-04 10:20:21 +00:00
|
|
|
goto error;
|
2012-11-12 14:33:55 +00:00
|
|
|
|
2013-03-31 18:03:42 +00:00
|
|
|
if (!(test->vm = virDomainObjNew(xmlopt)))
|
2012-08-20 13:06:21 +00:00
|
|
|
goto error;
|
|
|
|
|
2013-07-25 09:02:00 +00:00
|
|
|
if (virNetSocketNewListenUNIX(path, 0700, getuid(), getgid(),
|
2012-08-20 13:06:21 +00:00
|
|
|
&test->server) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2013-07-22 14:59:22 +00:00
|
|
|
memset(src, 0, sizeof(*src));
|
|
|
|
src->type = VIR_DOMAIN_CHR_TYPE_UNIX;
|
|
|
|
src->data.nix.path = (char *)path;
|
|
|
|
src->data.nix.listen = false;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
|
|
|
if (virNetSocketListen(test->server, 1) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2013-07-22 14:59:22 +00:00
|
|
|
cleanup:
|
|
|
|
return test;
|
|
|
|
|
|
|
|
error:
|
|
|
|
VIR_FREE(tmpdir_template);
|
|
|
|
qemuMonitorTestFree(test);
|
|
|
|
test = NULL;
|
|
|
|
goto cleanup;
|
|
|
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
static int
|
|
|
|
qemuMonitorCommonTestInit(qemuMonitorTestPtr test)
|
|
|
|
{
|
2013-07-25 09:48:11 +00:00
|
|
|
int events = VIR_EVENT_HANDLE_READABLE;
|
|
|
|
|
2013-07-22 14:59:22 +00:00
|
|
|
if (!test)
|
|
|
|
return -1;
|
2012-08-20 13:06:21 +00:00
|
|
|
|
|
|
|
if (virNetSocketAccept(test->server, &test->client) < 0)
|
|
|
|
goto error;
|
|
|
|
|
2013-07-22 14:59:22 +00:00
|
|
|
if (!test->client)
|
2012-09-06 15:14:25 +00:00
|
|
|
goto error;
|
|
|
|
|
2013-07-25 09:48:11 +00:00
|
|
|
if (test->outgoingLength > 0)
|
|
|
|
events = VIR_EVENT_HANDLE_WRITABLE;
|
|
|
|
|
2012-08-20 13:06:21 +00:00
|
|
|
if (virNetSocketAddIOCallback(test->client,
|
2013-07-25 09:48:11 +00:00
|
|
|
events,
|
2012-08-20 13:06:21 +00:00
|
|
|
qemuMonitorTestIO,
|
|
|
|
test,
|
|
|
|
NULL) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virMutexLock(&test->lock);
|
|
|
|
if (virThreadCreate(&test->thread,
|
|
|
|
true,
|
|
|
|
qemuMonitorTestWorker,
|
|
|
|
test) < 0) {
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
goto error;
|
|
|
|
}
|
|
|
|
test->running = true;
|
|
|
|
virMutexUnlock(&test->lock);
|
|
|
|
|
2013-07-22 14:59:22 +00:00
|
|
|
return 0;
|
|
|
|
|
|
|
|
error:
|
|
|
|
qemuMonitorTestFree(test);
|
|
|
|
return -1;
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
#define QEMU_JSON_GREETING "{\"QMP\":"\
|
|
|
|
" {\"version\":"\
|
|
|
|
" {\"qemu\":"\
|
|
|
|
" {\"micro\": 1,"\
|
|
|
|
" \"minor\": 0,"\
|
|
|
|
" \"major\": 1"\
|
|
|
|
" },"\
|
|
|
|
" \"package\": \"(qemu-kvm-1.0.1)"\
|
|
|
|
" \"},"\
|
|
|
|
" \"capabilities\": []"\
|
|
|
|
" }"\
|
|
|
|
"}"
|
|
|
|
/* We skip the normal handshake reply of "{\"execute\":\"qmp_capabilities\"}" */
|
|
|
|
|
|
|
|
#define QEMU_TEXT_GREETING "QEMU 1.0,1 monitor - type 'help' for more information"
|
|
|
|
|
|
|
|
qemuMonitorTestPtr
|
|
|
|
qemuMonitorTestNew(bool json, virDomainXMLOptionPtr xmlopt)
|
|
|
|
{
|
|
|
|
qemuMonitorTestPtr test = NULL;
|
|
|
|
virDomainChrSourceDef src;
|
|
|
|
|
|
|
|
if (!(test = qemuMonitorCommonTestNew(xmlopt, &src)))
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
test->json = json;
|
|
|
|
if (!(test->mon = qemuMonitorOpen(test->vm,
|
|
|
|
&src,
|
|
|
|
json,
|
2013-07-25 09:48:11 +00:00
|
|
|
&qemuMonitorTestCallbacks)))
|
2013-07-22 14:59:22 +00:00
|
|
|
goto error;
|
|
|
|
|
|
|
|
virObjectLock(test->mon);
|
|
|
|
|
|
|
|
if (qemuMonitorTestAddReponse(test, json ?
|
|
|
|
QEMU_JSON_GREETING :
|
|
|
|
QEMU_TEXT_GREETING) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
if (qemuMonitorCommonTestInit(test) < 0)
|
|
|
|
goto error;
|
|
|
|
|
|
|
|
virDomainChrSourceDefClear(&src);
|
|
|
|
|
2012-08-20 13:06:21 +00:00
|
|
|
return test;
|
|
|
|
|
|
|
|
error:
|
|
|
|
qemuMonitorTestFree(test);
|
2013-07-22 14:59:22 +00:00
|
|
|
return NULL;
|
2012-08-20 13:06:21 +00:00
|
|
|
}
|
|
|
|
|
2013-07-18 14:17:31 +00:00
|
|
|
|
|
|
|
qemuMonitorPtr
|
|
|
|
qemuMonitorTestGetMonitor(qemuMonitorTestPtr test)
|
2012-08-20 13:06:21 +00:00
|
|
|
{
|
|
|
|
return test->mon;
|
|
|
|
}
|