mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2025-01-03 03:25:20 +00:00
Provide a simple object for encoding/decoding RPC messages
This provides a new struct that contains a buffer for the RPC message header+payload, as well as a decoded copy of the message header. There is an API for applying a XDR encoding & decoding of the message headers and payloads. There are also APIs for maintaining a simple FIFO queue of message instances. Expected usage scenarios are: To send a message msg = virNetMessageNew() ...fill in msg->header fields.. virNetMessageEncodeHeader(msg) ...loook at msg->header fields to determine payload filter virNetMessageEncodePayload(msg, xdrfilter, data) ...send msg->bufferLength worth of data from buffer To receive a message msg = virNetMessageNew() ...read VIR_NET_MESSAGE_LEN_MAX of data into buffer virNetMessageDecodeLength(msg) ...read msg->bufferLength-msg->bufferOffset of data into buffer virNetMessageDecodeHeader(msg) ...look at msg->header fields to determine payload filter virNetMessageDecodePayload(msg, xdrfilter, data) ...run payload processor * src/Makefile.am: Add to libvirt-net-rpc.la * src/rpc/virnetmessage.c, src/rpc/virnetmessage.h: Internal message handling API. * testutils.c, testutils.h: Helper for printing binary differences * virnetmessagetest.c: Validate all XDR encoding/decoding
This commit is contained in:
parent
980a132a24
commit
ceacc1dd4f
1
cfg.mk
1
cfg.mk
@ -125,6 +125,7 @@ useless_free_options = \
|
||||
--name=virInterfaceProtocolDefFree \
|
||||
--name=virJSONValueFree \
|
||||
--name=virLastErrFreeData \
|
||||
--name=virNetMessageFree \
|
||||
--name=virNWFilterDefFree \
|
||||
--name=virNWFilterEntryFree \
|
||||
--name=virNWFilterHashTableFree \
|
||||
|
@ -69,6 +69,7 @@ src/qemu/qemu_monitor_text.c
|
||||
src/qemu/qemu_process.c
|
||||
src/remote/remote_client_bodies.h
|
||||
src/remote/remote_driver.c
|
||||
src/rpc/virnetmessage.c
|
||||
src/secret/secret_driver.c
|
||||
src/security/security_apparmor.c
|
||||
src/security/security_dac.c
|
||||
|
@ -1191,6 +1191,7 @@ endif
|
||||
noinst_LTLIBRARIES += libvirt-net-rpc.la
|
||||
|
||||
libvirt_net_rpc_la_SOURCES = \
|
||||
rpc/virnetmessage.h rpc/virnetmessage.c \
|
||||
rpc/virnetprotocol.h rpc/virnetprotocol.c
|
||||
libvirt_net_rpc_la_CFLAGS = \
|
||||
$(AM_CFLAGS)
|
||||
|
365
src/rpc/virnetmessage.c
Normal file
365
src/rpc/virnetmessage.c
Normal file
@ -0,0 +1,365 @@
|
||||
/*
|
||||
* virnetmessage.c: basic RPC message encoding/decoding
|
||||
*
|
||||
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
|
||||
#include "virnetmessage.h"
|
||||
#include "memory.h"
|
||||
#include "virterror_internal.h"
|
||||
#include "logging.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_RPC
|
||||
#define virNetError(code, ...) \
|
||||
virReportErrorHelper(VIR_FROM_THIS, code, __FILE__, \
|
||||
__FUNCTION__, __LINE__, __VA_ARGS__)
|
||||
|
||||
virNetMessagePtr virNetMessageNew(void)
|
||||
{
|
||||
virNetMessagePtr msg;
|
||||
|
||||
if (VIR_ALLOC(msg) < 0) {
|
||||
virReportOOMError();
|
||||
return NULL;
|
||||
}
|
||||
|
||||
VIR_DEBUG("msg=%p", msg);
|
||||
|
||||
return msg;
|
||||
}
|
||||
|
||||
void virNetMessageFree(virNetMessagePtr msg)
|
||||
{
|
||||
if (!msg)
|
||||
return;
|
||||
|
||||
VIR_DEBUG("msg=%p", msg);
|
||||
|
||||
VIR_FREE(msg);
|
||||
}
|
||||
|
||||
void virNetMessageQueuePush(virNetMessagePtr *queue, virNetMessagePtr msg)
|
||||
{
|
||||
virNetMessagePtr tmp = *queue;
|
||||
|
||||
if (tmp) {
|
||||
while (tmp->next)
|
||||
tmp = tmp->next;
|
||||
tmp->next = msg;
|
||||
} else {
|
||||
*queue = msg;
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
virNetMessagePtr virNetMessageQueueServe(virNetMessagePtr *queue)
|
||||
{
|
||||
virNetMessagePtr tmp = *queue;
|
||||
|
||||
if (tmp) {
|
||||
*queue = tmp->next;
|
||||
tmp->next = NULL;
|
||||
}
|
||||
|
||||
return tmp;
|
||||
}
|
||||
|
||||
|
||||
int virNetMessageDecodeLength(virNetMessagePtr msg)
|
||||
{
|
||||
XDR xdr;
|
||||
unsigned int len;
|
||||
int ret = -1;
|
||||
|
||||
xdrmem_create(&xdr, msg->buffer,
|
||||
msg->bufferLength, XDR_DECODE);
|
||||
if (!xdr_u_int(&xdr, &len)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to decode message length"));
|
||||
goto cleanup;
|
||||
}
|
||||
msg->bufferOffset = xdr_getpos(&xdr);
|
||||
|
||||
if (len < VIR_NET_MESSAGE_LEN_MAX) {
|
||||
virNetError(VIR_ERR_RPC, "%s",
|
||||
_("packet received from server too small"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Length includes length word - adjust to real length to read. */
|
||||
len -= VIR_NET_MESSAGE_LEN_MAX;
|
||||
|
||||
if (len > VIR_NET_MESSAGE_MAX) {
|
||||
virNetError(VIR_ERR_RPC, "%s",
|
||||
_("packet received from server too large"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
/* Extend our declared buffer length and carry
|
||||
on reading the header + payload */
|
||||
msg->bufferLength += len;
|
||||
|
||||
VIR_DEBUG("Got length, now need %zu total (%u more)",
|
||||
msg->bufferLength, len);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
xdr_destroy(&xdr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @msg: the complete incoming message, whose header to decode
|
||||
*
|
||||
* Decodes the header part of the message, but does not
|
||||
* validate the decoded fields in the header. It expects
|
||||
* bufferLength to refer to length of the data packet. Upon
|
||||
* return bufferOffset will refer to the amount of the packet
|
||||
* consumed by decoding of the header.
|
||||
*
|
||||
* returns 0 if successfully decoded, -1 upon fatal error
|
||||
*/
|
||||
int virNetMessageDecodeHeader(virNetMessagePtr msg)
|
||||
{
|
||||
XDR xdr;
|
||||
int ret = -1;
|
||||
|
||||
msg->bufferOffset = VIR_NET_MESSAGE_LEN_MAX;
|
||||
|
||||
/* Parse the header. */
|
||||
xdrmem_create(&xdr,
|
||||
msg->buffer + msg->bufferOffset,
|
||||
msg->bufferLength - msg->bufferOffset,
|
||||
XDR_DECODE);
|
||||
|
||||
if (!xdr_virNetMessageHeader(&xdr, &msg->header)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to decode message header"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
msg->bufferOffset += xdr_getpos(&xdr);
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
xdr_destroy(&xdr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
/*
|
||||
* @msg: the outgoing message, whose header to encode
|
||||
*
|
||||
* Encodes the length word and header of the message, setting the
|
||||
* message offset ready to encode the payload. Leaves space
|
||||
* for the length field later. Upon return bufferLength will
|
||||
* refer to the total available space for message, while
|
||||
* bufferOffset will refer to current space used by header
|
||||
*
|
||||
* returns 0 if successfully encoded, -1 upon fatal error
|
||||
*/
|
||||
int virNetMessageEncodeHeader(virNetMessagePtr msg)
|
||||
{
|
||||
XDR xdr;
|
||||
int ret = -1;
|
||||
unsigned int len = 0;
|
||||
|
||||
msg->bufferLength = sizeof(msg->buffer);
|
||||
msg->bufferOffset = 0;
|
||||
|
||||
/* Format the header. */
|
||||
xdrmem_create(&xdr,
|
||||
msg->buffer,
|
||||
msg->bufferLength,
|
||||
XDR_ENCODE);
|
||||
|
||||
/* The real value is filled in shortly */
|
||||
if (!xdr_u_int(&xdr, &len)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message length"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
if (!xdr_virNetMessageHeader(&xdr, &msg->header)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message header"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
len = xdr_getpos(&xdr);
|
||||
xdr_setpos(&xdr, 0);
|
||||
|
||||
/* Fill in current length - may be re-written later
|
||||
* if a payload is added
|
||||
*/
|
||||
if (!xdr_u_int(&xdr, &len)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to re-encode message length"));
|
||||
goto cleanup;
|
||||
}
|
||||
|
||||
msg->bufferOffset += len;
|
||||
|
||||
ret = 0;
|
||||
|
||||
cleanup:
|
||||
xdr_destroy(&xdr);
|
||||
return ret;
|
||||
}
|
||||
|
||||
|
||||
int virNetMessageEncodePayload(virNetMessagePtr msg,
|
||||
xdrproc_t filter,
|
||||
void *data)
|
||||
{
|
||||
XDR xdr;
|
||||
unsigned int msglen;
|
||||
|
||||
/* Serialise payload of the message. This assumes that
|
||||
* virNetMessageEncodeHeader has already been run, so
|
||||
* just appends to that data */
|
||||
xdrmem_create(&xdr, msg->buffer + msg->bufferOffset,
|
||||
msg->bufferLength - msg->bufferOffset, XDR_ENCODE);
|
||||
|
||||
if (!(*filter)(&xdr, data)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message payload"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get the length stored in buffer. */
|
||||
msg->bufferOffset += xdr_getpos(&xdr);
|
||||
xdr_destroy(&xdr);
|
||||
|
||||
/* Re-encode the length word. */
|
||||
VIR_DEBUG("Encode length as %zu", msg->bufferOffset);
|
||||
xdrmem_create(&xdr, msg->buffer, VIR_NET_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
|
||||
msglen = msg->bufferOffset;
|
||||
if (!xdr_u_int(&xdr, &msglen)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message length"));
|
||||
goto error;
|
||||
}
|
||||
xdr_destroy(&xdr);
|
||||
|
||||
msg->bufferLength = msg->bufferOffset;
|
||||
msg->bufferOffset = 0;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
xdr_destroy(&xdr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int virNetMessageDecodePayload(virNetMessagePtr msg,
|
||||
xdrproc_t filter,
|
||||
void *data)
|
||||
{
|
||||
XDR xdr;
|
||||
|
||||
/* Deserialise payload of the message. This assumes that
|
||||
* virNetMessageDecodeHeader has already been run, so
|
||||
* just start from after that data */
|
||||
xdrmem_create(&xdr, msg->buffer + msg->bufferOffset,
|
||||
msg->bufferLength - msg->bufferOffset, XDR_DECODE);
|
||||
|
||||
if (!(*filter)(&xdr, data)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to decode message payload"));
|
||||
goto error;
|
||||
}
|
||||
|
||||
/* Get the length stored in buffer. */
|
||||
msg->bufferLength += xdr_getpos(&xdr);
|
||||
xdr_destroy(&xdr);
|
||||
return 0;
|
||||
|
||||
error:
|
||||
xdr_destroy(&xdr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
int virNetMessageEncodePayloadRaw(virNetMessagePtr msg,
|
||||
const char *data,
|
||||
size_t len)
|
||||
{
|
||||
XDR xdr;
|
||||
unsigned int msglen;
|
||||
|
||||
if ((msg->bufferLength - msg->bufferOffset) < len) {
|
||||
virNetError(VIR_ERR_RPC,
|
||||
_("Stream data too long to send (%zu bytes needed, %zu bytes available)"),
|
||||
len, (msg->bufferLength - msg->bufferOffset));
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(msg->buffer + msg->bufferOffset, data, len);
|
||||
msg->bufferOffset += len;
|
||||
|
||||
/* Re-encode the length word. */
|
||||
VIR_DEBUG("Encode length as %zu", msg->bufferOffset);
|
||||
xdrmem_create(&xdr, msg->buffer, VIR_NET_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
|
||||
msglen = msg->bufferOffset;
|
||||
if (!xdr_u_int(&xdr, &msglen)) {
|
||||
virNetError(VIR_ERR_RPC, "%s", _("Unable to encode message length"));
|
||||
goto error;
|
||||
}
|
||||
xdr_destroy(&xdr);
|
||||
|
||||
msg->bufferLength = msg->bufferOffset;
|
||||
msg->bufferOffset = 0;
|
||||
return 0;
|
||||
|
||||
error:
|
||||
xdr_destroy(&xdr);
|
||||
return -1;
|
||||
}
|
||||
|
||||
|
||||
void virNetMessageSaveError(virNetMessageErrorPtr rerr)
|
||||
{
|
||||
/* This func may be called several times & the first
|
||||
* error is the one we want because we don't want
|
||||
* cleanup code overwriting the first one.
|
||||
*/
|
||||
if (rerr->code != VIR_ERR_OK)
|
||||
return;
|
||||
|
||||
virErrorPtr verr = virGetLastError();
|
||||
if (verr) {
|
||||
rerr->code = verr->code;
|
||||
rerr->domain = verr->domain;
|
||||
rerr->message = verr->message ? malloc(sizeof(char*)) : NULL;
|
||||
if (rerr->message) *rerr->message = strdup(verr->message);
|
||||
rerr->level = verr->level;
|
||||
rerr->str1 = verr->str1 ? malloc(sizeof(char*)) : NULL;
|
||||
if (rerr->str1) *rerr->str1 = strdup(verr->str1);
|
||||
rerr->str2 = verr->str2 ? malloc(sizeof(char*)) : NULL;
|
||||
if (rerr->str2) *rerr->str2 = strdup(verr->str2);
|
||||
rerr->str3 = verr->str3 ? malloc(sizeof(char*)) : NULL;
|
||||
if (rerr->str3) *rerr->str3 = strdup(verr->str3);
|
||||
rerr->int1 = verr->int1;
|
||||
rerr->int2 = verr->int2;
|
||||
} else {
|
||||
rerr->code = VIR_ERR_INTERNAL_ERROR;
|
||||
rerr->domain = VIR_FROM_RPC;
|
||||
rerr->message = malloc(sizeof(char*));
|
||||
if (rerr->message) *rerr->message = strdup(_("Library function returned error but did not set virError"));
|
||||
rerr->level = VIR_ERR_ERROR;
|
||||
}
|
||||
}
|
80
src/rpc/virnetmessage.h
Normal file
80
src/rpc/virnetmessage.h
Normal file
@ -0,0 +1,80 @@
|
||||
/*
|
||||
* virnetmessage.h: basic RPC message encoding/decoding
|
||||
*
|
||||
* Copyright (C) 2010-2011 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*/
|
||||
|
||||
#ifndef __VIR_NET_MESSAGE_H__
|
||||
# define __VIR_NET_MESSAGE_H__
|
||||
|
||||
# include "virnetprotocol.h"
|
||||
|
||||
typedef struct virNetMessageHeader *virNetMessageHeaderPtr;
|
||||
typedef struct virNetMessageError *virNetMessageErrorPtr;
|
||||
|
||||
typedef struct _virNetMessage virNetMessage;
|
||||
typedef virNetMessage *virNetMessagePtr;
|
||||
|
||||
/* Never allocate this (huge) buffer on the stack. Always
|
||||
* use virNetMessageNew() to allocate on the heap
|
||||
*/
|
||||
struct _virNetMessage {
|
||||
char buffer[VIR_NET_MESSAGE_MAX + VIR_NET_MESSAGE_LEN_MAX];
|
||||
size_t bufferLength;
|
||||
size_t bufferOffset;
|
||||
|
||||
virNetMessageHeader header;
|
||||
|
||||
virNetMessagePtr next;
|
||||
};
|
||||
|
||||
|
||||
virNetMessagePtr virNetMessageNew(void);
|
||||
|
||||
void virNetMessageFree(virNetMessagePtr msg);
|
||||
|
||||
virNetMessagePtr virNetMessageQueueServe(virNetMessagePtr *queue)
|
||||
ATTRIBUTE_NONNULL(1);
|
||||
void virNetMessageQueuePush(virNetMessagePtr *queue,
|
||||
virNetMessagePtr msg)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2);
|
||||
|
||||
int virNetMessageEncodeHeader(virNetMessagePtr msg)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||
int virNetMessageDecodeLength(virNetMessagePtr msg)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||
int virNetMessageDecodeHeader(virNetMessagePtr msg)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
int virNetMessageEncodePayload(virNetMessagePtr msg,
|
||||
xdrproc_t filter,
|
||||
void *data)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||
int virNetMessageDecodePayload(virNetMessagePtr msg,
|
||||
xdrproc_t filter,
|
||||
void *data)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_NONNULL(2) ATTRIBUTE_NONNULL(2) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
int virNetMessageEncodePayloadRaw(virNetMessagePtr msg,
|
||||
const char *buf,
|
||||
size_t len)
|
||||
ATTRIBUTE_NONNULL(1) ATTRIBUTE_RETURN_CHECK;
|
||||
|
||||
void virNetMessageSaveError(virNetMessageErrorPtr rerr)
|
||||
ATTRIBUTE_NONNULL(1);
|
||||
|
||||
#endif /* __VIR_NET_MESSAGE_H__ */
|
1
tests/.gitignore
vendored
1
tests/.gitignore
vendored
@ -30,6 +30,7 @@ statstest
|
||||
storagepoolxml2xmltest
|
||||
storagevolxml2xmltest
|
||||
virbuftest
|
||||
virnetmessagetest
|
||||
virshtest
|
||||
vmx2xmltest
|
||||
xencapstest
|
||||
|
@ -78,7 +78,7 @@ EXTRA_DIST = \
|
||||
check_PROGRAMS = virshtest conftest sockettest \
|
||||
nodeinfotest qparamtest virbuftest \
|
||||
commandtest commandhelper seclabeltest \
|
||||
hashtest
|
||||
hashtest virnetmessagetest
|
||||
|
||||
if WITH_XEN
|
||||
check_PROGRAMS += xml2sexprtest sexpr2xmltest \
|
||||
@ -184,6 +184,7 @@ TESTS = virshtest \
|
||||
commandtest \
|
||||
seclabeltest \
|
||||
hashtest \
|
||||
virnetmessagetest \
|
||||
$(test_scripts)
|
||||
|
||||
if WITH_XEN
|
||||
@ -400,6 +401,12 @@ commandhelper_SOURCES = \
|
||||
commandhelper_CFLAGS = -Dabs_builddir="\"`pwd`\""
|
||||
commandhelper_LDADD = $(LDADDS)
|
||||
|
||||
virnetmessagetest_SOURCES = \
|
||||
virnetmessagetest.c testutils.h testutils.c
|
||||
virnetmessagetest_CFLAGS = -Dabs_builddir="\"$(abs_builddir)\""
|
||||
virnetmessagetest_LDADD = ../src/libvirt-net-rpc.la $(LDADDS)
|
||||
|
||||
|
||||
seclabeltest_SOURCES = \
|
||||
seclabeltest.c
|
||||
seclabeltest_LDADD = ../src/libvirt_driver_security.la $(LDADDS)
|
||||
|
@ -370,6 +370,70 @@ int virtTestDifference(FILE *stream,
|
||||
return 0;
|
||||
}
|
||||
|
||||
/**
|
||||
* @param stream: output stream write to differences to
|
||||
* @param expect: expected output text
|
||||
* @param actual: actual output text
|
||||
*
|
||||
* Display expected and actual output text, trimmed to
|
||||
* first and last characters at which differences occur
|
||||
*/
|
||||
int virtTestDifferenceBin(FILE *stream,
|
||||
const char *expect,
|
||||
const char *actual,
|
||||
size_t length)
|
||||
{
|
||||
size_t start = 0, end = length;
|
||||
ssize_t i;
|
||||
|
||||
if (!virTestGetDebug())
|
||||
return 0;
|
||||
|
||||
if (virTestGetDebug() < 2) {
|
||||
/* Skip to first character where they differ */
|
||||
for (i = 0 ; i < length ; i++) {
|
||||
if (expect[i] != actual[i]) {
|
||||
start = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
/* Work backwards to last character where they differ */
|
||||
for (i = (length -1) ; i >= 0 ; i--) {
|
||||
if (expect[i] != actual[i]) {
|
||||
end = i;
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
/* Round to nearest boundary of 4, except that last world can be short */
|
||||
start -= (start % 4);
|
||||
end += 4 - (end % 4);
|
||||
if (end >= length)
|
||||
end = length - 1;
|
||||
|
||||
/* Show the trimmed differences */
|
||||
fprintf(stream, "\nExpect [ Region %d-%d", (int)start, (int)end);
|
||||
for (i = start; i < end ; i++) {
|
||||
if ((i % 4) == 0)
|
||||
fprintf(stream, "\n ");
|
||||
fprintf(stream, "0x%02x, ", ((int)expect[i])&0xff);
|
||||
}
|
||||
fprintf(stream, "]\n");
|
||||
fprintf(stream, "Actual [ Region %d-%d", (int)start, (int)end);
|
||||
for (i = start; i < end ; i++) {
|
||||
if ((i % 4) == 0)
|
||||
fprintf(stream, "\n ");
|
||||
fprintf(stream, "0x%02x, ", ((int)actual[i])&0xff);
|
||||
}
|
||||
fprintf(stream, "]\n");
|
||||
|
||||
/* Pad to line up with test name ... in virTestRun */
|
||||
fprintf(stream, " ... ");
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
#if TEST_OOM
|
||||
static void
|
||||
virtTestErrorFuncQuiet(void *data ATTRIBUTE_UNUSED,
|
||||
|
@ -36,6 +36,10 @@ int virtTestClearLineRegex(const char *pattern,
|
||||
int virtTestDifference(FILE *stream,
|
||||
const char *expect,
|
||||
const char *actual);
|
||||
int virtTestDifferenceBin(FILE *stream,
|
||||
const char *expect,
|
||||
const char *actual,
|
||||
size_t length);
|
||||
|
||||
unsigned int virTestGetDebug(void);
|
||||
unsigned int virTestGetVerbose(void);
|
||||
|
495
tests/virnetmessagetest.c
Normal file
495
tests/virnetmessagetest.c
Normal file
@ -0,0 +1,495 @@
|
||||
/*
|
||||
* Copyright (C) 2011 Red Hat, Inc.
|
||||
*
|
||||
* 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
|
||||
* License along with this library; if not, write to the Free Software
|
||||
* Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA
|
||||
*
|
||||
* Author: Daniel P. Berrange <berrange@redhat.com>
|
||||
*/
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <stdlib.h>
|
||||
#include <signal.h>
|
||||
|
||||
#include "testutils.h"
|
||||
#include "util.h"
|
||||
#include "virterror_internal.h"
|
||||
#include "memory.h"
|
||||
#include "logging.h"
|
||||
|
||||
#include "rpc/virnetmessage.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_RPC
|
||||
|
||||
static int testMessageHeaderEncode(const void *args ATTRIBUTE_UNUSED)
|
||||
{
|
||||
static virNetMessage msg;
|
||||
static const char expect[] = {
|
||||
0x00, 0x00, 0x00, 0x1c, /* Length */
|
||||
0x11, 0x22, 0x33, 0x44, /* Program */
|
||||
0x00, 0x00, 0x00, 0x01, /* Version */
|
||||
0x00, 0x00, 0x06, 0x66, /* Procedure */
|
||||
0x00, 0x00, 0x00, 0x00, /* Type */
|
||||
0x00, 0x00, 0x00, 0x99, /* Serial */
|
||||
0x00, 0x00, 0x00, 0x00, /* Status */
|
||||
};
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.header.prog = 0x11223344;
|
||||
msg.header.vers = 0x01;
|
||||
msg.header.proc = 0x666;
|
||||
msg.header.type = VIR_NET_CALL;
|
||||
msg.header.serial = 0x99;
|
||||
msg.header.status = VIR_NET_OK;
|
||||
|
||||
if (virNetMessageEncodeHeader(&msg) < 0)
|
||||
return -1;
|
||||
|
||||
if (ARRAY_CARDINALITY(expect) != msg.bufferOffset) {
|
||||
VIR_DEBUG("Expect message offset %zu got %zu",
|
||||
sizeof(expect), msg.bufferOffset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferLength != sizeof(msg.buffer)) {
|
||||
VIR_DEBUG("Expect message offset %zu got %zu",
|
||||
sizeof(msg.buffer), msg.bufferLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(expect, msg.buffer, sizeof(expect)) != 0) {
|
||||
virtTestDifferenceBin(stderr, expect, msg.buffer, sizeof(expect));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int testMessageHeaderDecode(const void *args ATTRIBUTE_UNUSED)
|
||||
{
|
||||
static virNetMessage msg = {
|
||||
.bufferOffset = 0,
|
||||
.bufferLength = 0x4,
|
||||
.buffer = {
|
||||
0x00, 0x00, 0x00, 0x1c, /* Length */
|
||||
0x11, 0x22, 0x33, 0x44, /* Program */
|
||||
0x00, 0x00, 0x00, 0x01, /* Version */
|
||||
0x00, 0x00, 0x06, 0x66, /* Procedure */
|
||||
0x00, 0x00, 0x00, 0x01, /* Type */
|
||||
0x00, 0x00, 0x00, 0x99, /* Serial */
|
||||
0x00, 0x00, 0x00, 0x01, /* Status */
|
||||
},
|
||||
.header = { 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
|
||||
msg.header.prog = 0x11223344;
|
||||
msg.header.vers = 0x01;
|
||||
msg.header.proc = 0x666;
|
||||
msg.header.type = VIR_NET_CALL;
|
||||
msg.header.serial = 0x99;
|
||||
msg.header.status = VIR_NET_OK;
|
||||
|
||||
if (virNetMessageDecodeLength(&msg) < 0) {
|
||||
VIR_DEBUG("Failed to decode message header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferOffset != 0x4) {
|
||||
VIR_DEBUG("Expecting offset %zu got %zu",
|
||||
(size_t)4, msg.bufferOffset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferLength != 0x1c) {
|
||||
VIR_DEBUG("Expecting length %zu got %zu",
|
||||
(size_t)0x1c, msg.bufferLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virNetMessageDecodeHeader(&msg) < 0) {
|
||||
VIR_DEBUG("Failed to decode message header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferOffset != msg.bufferLength) {
|
||||
VIR_DEBUG("Expect message offset %zu got %zu",
|
||||
msg.bufferOffset, msg.bufferLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.header.prog != 0x11223344) {
|
||||
VIR_DEBUG("Expect prog %d got %d",
|
||||
0x11223344, msg.header.prog);
|
||||
return -1;
|
||||
}
|
||||
if (msg.header.vers != 0x1) {
|
||||
VIR_DEBUG("Expect vers %d got %d",
|
||||
0x11223344, msg.header.vers);
|
||||
return -1;
|
||||
}
|
||||
if (msg.header.proc != 0x666) {
|
||||
VIR_DEBUG("Expect proc %d got %d",
|
||||
0x666, msg.header.proc);
|
||||
return -1;
|
||||
}
|
||||
if (msg.header.type != VIR_NET_REPLY) {
|
||||
VIR_DEBUG("Expect type %d got %d",
|
||||
VIR_NET_REPLY, msg.header.type);
|
||||
return -1;
|
||||
}
|
||||
if (msg.header.serial != 0x99) {
|
||||
VIR_DEBUG("Expect serial %d got %d",
|
||||
0x99, msg.header.serial);
|
||||
return -1;
|
||||
}
|
||||
if (msg.header.status != VIR_NET_ERROR) {
|
||||
VIR_DEBUG("Expect status %d got %d",
|
||||
VIR_NET_ERROR, msg.header.status);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int testMessagePayloadEncode(const void *args ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virNetMessageError err;
|
||||
static virNetMessage msg;
|
||||
static const char expect[] = {
|
||||
0x00, 0x00, 0x00, 0x74, /* Length */
|
||||
0x11, 0x22, 0x33, 0x44, /* Program */
|
||||
0x00, 0x00, 0x00, 0x01, /* Version */
|
||||
0x00, 0x00, 0x06, 0x66, /* Procedure */
|
||||
0x00, 0x00, 0x00, 0x02, /* Type */
|
||||
0x00, 0x00, 0x00, 0x99, /* Serial */
|
||||
0x00, 0x00, 0x00, 0x01, /* Status */
|
||||
|
||||
0x00, 0x00, 0x00, 0x01, /* Error code */
|
||||
0x00, 0x00, 0x00, 0x07, /* Error domain */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error message pointer */
|
||||
0x00, 0x00, 0x00, 0x0b, /* Error message length */
|
||||
'H', 'e', 'l', 'l', /* Error message string */
|
||||
'o', ' ', 'W', 'o',
|
||||
'r', 'l', 'd', '\0',
|
||||
0x00, 0x00, 0x00, 0x02, /* Error level */
|
||||
0x00, 0x00, 0x00, 0x00, /* Error domain pointer */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error str1 pointer */
|
||||
0x00, 0x00, 0x00, 0x03, /* Error str1 length */
|
||||
'O', 'n', 'e', '\0', /* Error str1 message */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error str2 pointer */
|
||||
0x00, 0x00, 0x00, 0x03, /* Error str2 length */
|
||||
'T', 'w', 'o', '\0', /* Error str2 message */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error str3 pointer */
|
||||
0x00, 0x00, 0x00, 0x05, /* Error str3 length */
|
||||
'T', 'h', 'r', 'e', /* Error str3 message */
|
||||
'e', '\0', '\0', '\0',
|
||||
0x00, 0x00, 0x00, 0x01, /* Error int1 */
|
||||
0x00, 0x00, 0x00, 0x02, /* Error int2 */
|
||||
0x00, 0x00, 0x00, 0x00, /* Error network pointer */
|
||||
};
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
memset(&err, 0, sizeof(err));
|
||||
|
||||
err.code = VIR_ERR_INTERNAL_ERROR;
|
||||
err.domain = VIR_FROM_RPC;
|
||||
if (VIR_ALLOC(err.message) < 0)
|
||||
return -1;
|
||||
*err.message = strdup("Hello World");
|
||||
err.level = VIR_ERR_ERROR;
|
||||
if (VIR_ALLOC(err.str1) < 0)
|
||||
return -1;
|
||||
*err.str1 = strdup("One");
|
||||
if (VIR_ALLOC(err.str2) < 0)
|
||||
return -1;
|
||||
*err.str2 = strdup("Two");
|
||||
if (VIR_ALLOC(err.str3) < 0)
|
||||
return -1;
|
||||
*err.str3 = strdup("Three");
|
||||
err.int1 = 1;
|
||||
err.int2 = 2;
|
||||
|
||||
msg.header.prog = 0x11223344;
|
||||
msg.header.vers = 0x01;
|
||||
msg.header.proc = 0x666;
|
||||
msg.header.type = VIR_NET_MESSAGE;
|
||||
msg.header.serial = 0x99;
|
||||
msg.header.status = VIR_NET_ERROR;
|
||||
|
||||
if (virNetMessageEncodeHeader(&msg) < 0)
|
||||
return -1;
|
||||
|
||||
if (virNetMessageEncodePayload(&msg, (xdrproc_t)xdr_virNetMessageError, &err) < 0)
|
||||
return -1;
|
||||
|
||||
if (ARRAY_CARDINALITY(expect) != msg.bufferLength) {
|
||||
VIR_DEBUG("Expect message length %zu got %zu",
|
||||
sizeof(expect), msg.bufferLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferOffset != 0) {
|
||||
VIR_DEBUG("Expect message offset 0 got %zu",
|
||||
msg.bufferOffset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(expect, msg.buffer, sizeof(expect)) != 0) {
|
||||
virtTestDifferenceBin(stderr, expect, msg.buffer, sizeof(expect));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int testMessagePayloadDecode(const void *args ATTRIBUTE_UNUSED)
|
||||
{
|
||||
virNetMessageError err;
|
||||
static virNetMessage msg = {
|
||||
.bufferOffset = 0,
|
||||
.bufferLength = 0x4,
|
||||
.buffer = {
|
||||
0x00, 0x00, 0x00, 0x74, /* Length */
|
||||
0x11, 0x22, 0x33, 0x44, /* Program */
|
||||
0x00, 0x00, 0x00, 0x01, /* Version */
|
||||
0x00, 0x00, 0x06, 0x66, /* Procedure */
|
||||
0x00, 0x00, 0x00, 0x02, /* Type */
|
||||
0x00, 0x00, 0x00, 0x99, /* Serial */
|
||||
0x00, 0x00, 0x00, 0x01, /* Status */
|
||||
|
||||
0x00, 0x00, 0x00, 0x01, /* Error code */
|
||||
0x00, 0x00, 0x00, 0x07, /* Error domain */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error message pointer */
|
||||
0x00, 0x00, 0x00, 0x0b, /* Error message length */
|
||||
'H', 'e', 'l', 'l', /* Error message string */
|
||||
'o', ' ', 'W', 'o',
|
||||
'r', 'l', 'd', '\0',
|
||||
0x00, 0x00, 0x00, 0x02, /* Error level */
|
||||
0x00, 0x00, 0x00, 0x00, /* Error domain pointer */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error str1 pointer */
|
||||
0x00, 0x00, 0x00, 0x03, /* Error str1 length */
|
||||
'O', 'n', 'e', '\0', /* Error str1 message */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error str2 pointer */
|
||||
0x00, 0x00, 0x00, 0x03, /* Error str2 length */
|
||||
'T', 'w', 'o', '\0', /* Error str2 message */
|
||||
0x00, 0x00, 0x00, 0x01, /* Error str3 pointer */
|
||||
0x00, 0x00, 0x00, 0x05, /* Error str3 length */
|
||||
'T', 'h', 'r', 'e', /* Error str3 message */
|
||||
'e', '\0', '\0', '\0',
|
||||
0x00, 0x00, 0x00, 0x01, /* Error int1 */
|
||||
0x00, 0x00, 0x00, 0x02, /* Error int2 */
|
||||
0x00, 0x00, 0x00, 0x00, /* Error network pointer */
|
||||
},
|
||||
.header = { 0, 0, 0, 0, 0, 0 },
|
||||
};
|
||||
memset(&err, 0, sizeof(err));
|
||||
|
||||
if (virNetMessageDecodeLength(&msg) < 0) {
|
||||
VIR_DEBUG("Failed to decode message header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferOffset != 0x4) {
|
||||
VIR_DEBUG("Expecting offset %zu got %zu",
|
||||
(size_t)4, msg.bufferOffset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferLength != 0x74) {
|
||||
VIR_DEBUG("Expecting length %zu got %zu",
|
||||
(size_t)0x74, msg.bufferLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virNetMessageDecodeHeader(&msg) < 0) {
|
||||
VIR_DEBUG("Failed to decode message header");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferOffset != 28) {
|
||||
VIR_DEBUG("Expect message offset %zu got %zu",
|
||||
msg.bufferOffset, (size_t)28);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferLength != 0x74) {
|
||||
VIR_DEBUG("Expecting length %zu got %zu",
|
||||
(size_t)0x1c, msg.bufferLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (virNetMessageDecodePayload(&msg, (xdrproc_t)xdr_virNetMessageError, &err) < 0) {
|
||||
VIR_DEBUG("Failed to decode message payload");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.code != VIR_ERR_INTERNAL_ERROR) {
|
||||
VIR_DEBUG("Expect code %d got %d",
|
||||
VIR_ERR_INTERNAL_ERROR, err.code);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.domain != VIR_FROM_RPC) {
|
||||
VIR_DEBUG("Expect domain %d got %d",
|
||||
VIR_ERR_RPC, err.domain);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.message == NULL ||
|
||||
STRNEQ(*err.message, "Hello World")) {
|
||||
VIR_DEBUG("Expect str1 'Hello World' got %s",
|
||||
err.message ? *err.message : "(null)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.dom != NULL) {
|
||||
VIR_DEBUG("Expect NULL dom");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.level != VIR_ERR_ERROR) {
|
||||
VIR_DEBUG("Expect leve %d got %d",
|
||||
VIR_ERR_ERROR, err.level);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.str1 == NULL ||
|
||||
STRNEQ(*err.str1, "One")) {
|
||||
VIR_DEBUG("Expect str1 'One' got %s",
|
||||
err.str1 ? *err.str1 : "(null)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.str2 == NULL ||
|
||||
STRNEQ(*err.str2, "Two")) {
|
||||
VIR_DEBUG("Expect str3 'Two' got %s",
|
||||
err.str2 ? *err.str2 : "(null)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.str3 == NULL ||
|
||||
STRNEQ(*err.str3, "Three")) {
|
||||
VIR_DEBUG("Expect str3 'Three' got %s",
|
||||
err.str3 ? *err.str3 : "(null)");
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.int1 != 1) {
|
||||
VIR_DEBUG("Expect int1 1 got %d",
|
||||
err.int1);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.int2 != 2) {
|
||||
VIR_DEBUG("Expect int2 2 got %d",
|
||||
err.int2);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (err.net != NULL) {
|
||||
VIR_DEBUG("Expect NULL network");
|
||||
return -1;
|
||||
}
|
||||
|
||||
xdr_free((xdrproc_t)xdr_virNetMessageError, (void*)&err);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int testMessagePayloadStreamEncode(const void *args ATTRIBUTE_UNUSED)
|
||||
{
|
||||
char stream[] = "The quick brown fox jumps over the lazy dog";
|
||||
static virNetMessage msg;
|
||||
static const char expect[] = {
|
||||
0x00, 0x00, 0x00, 0x47, /* Length */
|
||||
0x11, 0x22, 0x33, 0x44, /* Program */
|
||||
0x00, 0x00, 0x00, 0x01, /* Version */
|
||||
0x00, 0x00, 0x06, 0x66, /* Procedure */
|
||||
0x00, 0x00, 0x00, 0x03, /* Type */
|
||||
0x00, 0x00, 0x00, 0x99, /* Serial */
|
||||
0x00, 0x00, 0x00, 0x02, /* Status */
|
||||
|
||||
'T', 'h', 'e', ' ',
|
||||
'q', 'u', 'i', 'c',
|
||||
'k', ' ', 'b', 'r',
|
||||
'o', 'w', 'n', ' ',
|
||||
'f', 'o', 'x', ' ',
|
||||
'j', 'u', 'm', 'p',
|
||||
's', ' ', 'o', 'v',
|
||||
'e', 'r', ' ', 't',
|
||||
'h', 'e', ' ', 'l',
|
||||
'a', 'z', 'y', ' ',
|
||||
'd', 'o', 'g',
|
||||
};
|
||||
memset(&msg, 0, sizeof(msg));
|
||||
|
||||
msg.header.prog = 0x11223344;
|
||||
msg.header.vers = 0x01;
|
||||
msg.header.proc = 0x666;
|
||||
msg.header.type = VIR_NET_STREAM;
|
||||
msg.header.serial = 0x99;
|
||||
msg.header.status = VIR_NET_CONTINUE;
|
||||
|
||||
if (virNetMessageEncodeHeader(&msg) < 0)
|
||||
return -1;
|
||||
|
||||
if (virNetMessageEncodePayloadRaw(&msg, stream, strlen(stream)) < 0)
|
||||
return -1;
|
||||
|
||||
if (ARRAY_CARDINALITY(expect) != msg.bufferLength) {
|
||||
VIR_DEBUG("Expect message length %zu got %zu",
|
||||
sizeof(expect), msg.bufferLength);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (msg.bufferOffset != 0) {
|
||||
VIR_DEBUG("Expect message offset 0 got %zu",
|
||||
msg.bufferOffset);
|
||||
return -1;
|
||||
}
|
||||
|
||||
if (memcmp(expect, msg.buffer, sizeof(expect)) != 0) {
|
||||
virtTestDifferenceBin(stderr, expect, msg.buffer, sizeof(expect));
|
||||
return -1;
|
||||
}
|
||||
|
||||
return 0;
|
||||
}
|
||||
|
||||
|
||||
static int
|
||||
mymain(void)
|
||||
{
|
||||
int ret = 0;
|
||||
|
||||
signal(SIGPIPE, SIG_IGN);
|
||||
|
||||
if (virtTestRun("Message Header Encode", 1, testMessageHeaderEncode, NULL) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (virtTestRun("Message Header Decode", 1, testMessageHeaderDecode, NULL) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (virtTestRun("Message Payload Encode", 1, testMessagePayloadEncode, NULL) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (virtTestRun("Message Payload Decode", 1, testMessagePayloadDecode, NULL) < 0)
|
||||
ret = -1;
|
||||
|
||||
if (virtTestRun("Message Payload Stream Encode", 1, testMessagePayloadStreamEncode, NULL) < 0)
|
||||
ret = -1;
|
||||
|
||||
return (ret==0 ? EXIT_SUCCESS : EXIT_FAILURE);
|
||||
}
|
||||
|
||||
VIRT_TEST_MAIN(mymain)
|
Loading…
Reference in New Issue
Block a user