mirror of
https://gitlab.uni-freiburg.de/opensourcevdi/spice-common
synced 2025-12-26 14:18:36 +00:00
Add helper code for agent messages
Add agent.h and agent.c to deal with some common agent job: - checking message from network and fixing network order. - send back file transfer status. Code based on Linux agent and Windows agent. AgentXxxx and agent_xxx are used to avoid conflicts with protocol. See agent.h for more detail on how to use these APIs. Signed-off-by: Frediano Ziglio <fziglio@redhat.com>
This commit is contained in:
parent
8470ef9df2
commit
bb03ff099b
@ -17,6 +17,8 @@ BUILT_SOURCES = $(CLIENT_MARSHALLERS) $(SERVER_MARSHALLERS)
|
||||
|
||||
noinst_LTLIBRARIES = libspice-common.la libspice-common-server.la libspice-common-client.la
|
||||
libspice_common_la_SOURCES = \
|
||||
agent.c \
|
||||
agent.h \
|
||||
backtrace.c \
|
||||
backtrace.h \
|
||||
canvas_utils.c \
|
||||
|
||||
343
common/agent.c
Normal file
343
common/agent.c
Normal file
@ -0,0 +1,343 @@
|
||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/*
|
||||
Copyright (C) 2020 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#include "agent.h"
|
||||
|
||||
#ifdef _WIN32
|
||||
// Windows is always little endian
|
||||
# define FIX_ENDIAN16(x) (x) = (x)
|
||||
# define FIX_ENDIAN32(x) (x) = (x)
|
||||
# define FIX_ENDIAN64(x) (x) = (x)
|
||||
#else
|
||||
# include <glib.h>
|
||||
# define FIX_ENDIAN16(x) (x) = GUINT16_FROM_LE(x)
|
||||
# define FIX_ENDIAN32(x) (x) = GUINT32_FROM_LE(x)
|
||||
# define FIX_ENDIAN64(x) (x) = GUINT64_FROM_LE(x)
|
||||
#endif
|
||||
|
||||
#include <spice/start-packed.h>
|
||||
typedef struct SPICE_ATTR_PACKED {
|
||||
uint16_t v;
|
||||
} uint16_unaligned_t;
|
||||
|
||||
typedef struct SPICE_ATTR_PACKED {
|
||||
uint32_t v;
|
||||
} uint32_unaligned_t;
|
||||
|
||||
typedef struct SPICE_ATTR_PACKED {
|
||||
uint64_t v;
|
||||
} uint64_unaligned_t;
|
||||
#include <spice/end-packed.h>
|
||||
|
||||
static const int agent_message_min_size[] =
|
||||
{
|
||||
-1, /* Does not exist */
|
||||
sizeof(VDAgentMouseState), /* VD_AGENT_MOUSE_STATE */
|
||||
sizeof(VDAgentMonitorsConfig), /* VD_AGENT_MONITORS_CONFIG */
|
||||
sizeof(VDAgentReply), /* VD_AGENT_REPLY */
|
||||
sizeof(VDAgentClipboard), /* VD_AGENT_CLIPBOARD */
|
||||
sizeof(VDAgentDisplayConfig), /* VD_AGENT_DISPLAY_CONFIG */
|
||||
sizeof(VDAgentAnnounceCapabilities), /* VD_AGENT_ANNOUNCE_CAPABILITIES */
|
||||
sizeof(VDAgentClipboardGrab), /* VD_AGENT_CLIPBOARD_GRAB */
|
||||
sizeof(VDAgentClipboardRequest), /* VD_AGENT_CLIPBOARD_REQUEST */
|
||||
sizeof(VDAgentClipboardRelease), /* VD_AGENT_CLIPBOARD_RELEASE */
|
||||
sizeof(VDAgentFileXferStartMessage), /* VD_AGENT_FILE_XFER_START */
|
||||
sizeof(VDAgentFileXferStatusMessage), /* VD_AGENT_FILE_XFER_STATUS */
|
||||
sizeof(VDAgentFileXferDataMessage), /* VD_AGENT_FILE_XFER_DATA */
|
||||
0, /* VD_AGENT_CLIENT_DISCONNECTED */
|
||||
sizeof(VDAgentMaxClipboard), /* VD_AGENT_MAX_CLIPBOARD */
|
||||
sizeof(VDAgentAudioVolumeSync), /* VD_AGENT_AUDIO_VOLUME_SYNC */
|
||||
sizeof(VDAgentGraphicsDeviceInfo), /* VD_AGENT_GRAPHICS_DEVICE_INFO */
|
||||
};
|
||||
|
||||
static AgentCheckResult
|
||||
agent_message_check_size(const VDAgentMessage *message_header,
|
||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||
{
|
||||
if (message_header->protocol != VD_AGENT_PROTOCOL) {
|
||||
return AGENT_CHECK_WRONG_PROTOCOL_VERSION;
|
||||
}
|
||||
|
||||
if (message_header->type >= SPICE_N_ELEMENTS(agent_message_min_size) ||
|
||||
agent_message_min_size[message_header->type] < 0) {
|
||||
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
||||
}
|
||||
|
||||
uint32_t min_size = agent_message_min_size[message_header->type];
|
||||
|
||||
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
|
||||
switch (message_header->type) {
|
||||
case VD_AGENT_CLIPBOARD_GRAB:
|
||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||
case VD_AGENT_CLIPBOARD:
|
||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||
min_size += 4;
|
||||
}
|
||||
}
|
||||
|
||||
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||
VD_AGENT_CAP_CLIPBOARD_GRAB_SERIAL)
|
||||
&& message_header->type == VD_AGENT_CLIPBOARD_GRAB) {
|
||||
min_size += 4;
|
||||
}
|
||||
|
||||
switch (message_header->type) {
|
||||
case VD_AGENT_MONITORS_CONFIG:
|
||||
case VD_AGENT_FILE_XFER_START:
|
||||
case VD_AGENT_FILE_XFER_DATA:
|
||||
case VD_AGENT_CLIPBOARD:
|
||||
case VD_AGENT_CLIPBOARD_GRAB:
|
||||
case VD_AGENT_AUDIO_VOLUME_SYNC:
|
||||
case VD_AGENT_ANNOUNCE_CAPABILITIES:
|
||||
case VD_AGENT_GRAPHICS_DEVICE_INFO:
|
||||
case VD_AGENT_FILE_XFER_STATUS:
|
||||
if (message_header->size < min_size) {
|
||||
return AGENT_CHECK_INVALID_SIZE;
|
||||
}
|
||||
break;
|
||||
case VD_AGENT_MOUSE_STATE:
|
||||
case VD_AGENT_DISPLAY_CONFIG:
|
||||
case VD_AGENT_REPLY:
|
||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||
case VD_AGENT_MAX_CLIPBOARD:
|
||||
case VD_AGENT_CLIENT_DISCONNECTED:
|
||||
if (message_header->size != min_size) {
|
||||
return AGENT_CHECK_INVALID_SIZE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
||||
}
|
||||
return AGENT_CHECK_NO_ERROR;
|
||||
}
|
||||
|
||||
static void uint16_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
|
||||
{
|
||||
uint32_t i;
|
||||
uint16_unaligned_t *msg = (uint16_unaligned_t *)(_msg + offset);
|
||||
|
||||
/* offset - size % 2 should be 0 - extra bytes are ignored */
|
||||
for (i = 0; i < (size - offset) / 2; i++) {
|
||||
FIX_ENDIAN16(msg[i].v);
|
||||
}
|
||||
}
|
||||
|
||||
static void uint32_from_le(uint8_t *_msg, uint32_t size, uint32_t offset)
|
||||
{
|
||||
uint32_t i;
|
||||
uint32_unaligned_t *msg = (uint32_unaligned_t *)(_msg + offset);
|
||||
|
||||
/* offset - size % 4 should be 0 - extra bytes are ignored */
|
||||
for (i = 0; i < (size - offset) / 4; i++) {
|
||||
FIX_ENDIAN32(msg[i].v);
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
agent_message_clipboard_from_le(const VDAgentMessage *message_header, uint8_t *data,
|
||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||
{
|
||||
size_t min_size = agent_message_min_size[message_header->type];
|
||||
uint32_unaligned_t *data_type = (uint32_unaligned_t *) data;
|
||||
|
||||
if (VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||
VD_AGENT_CAP_CLIPBOARD_SELECTION)) {
|
||||
min_size += 4;
|
||||
data_type++;
|
||||
}
|
||||
|
||||
switch (message_header->type) {
|
||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||
case VD_AGENT_CLIPBOARD:
|
||||
FIX_ENDIAN32(data_type->v);
|
||||
break;
|
||||
case VD_AGENT_CLIPBOARD_GRAB:
|
||||
uint32_from_le(data, message_header->size, min_size);
|
||||
break;
|
||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||
// empty
|
||||
break;
|
||||
}
|
||||
}
|
||||
|
||||
static void
|
||||
agent_message_file_xfer_from_le(const VDAgentMessage *message_header, uint8_t *data)
|
||||
{
|
||||
uint32_unaligned_t *id = (uint32_unaligned_t *)data;
|
||||
FIX_ENDIAN32(id->v);
|
||||
id++; // result
|
||||
|
||||
switch (message_header->type) {
|
||||
case VD_AGENT_FILE_XFER_DATA: {
|
||||
VDAgentFileXferDataMessage *msg = (VDAgentFileXferDataMessage *) data;
|
||||
FIX_ENDIAN64(msg->size);
|
||||
break;
|
||||
}
|
||||
case VD_AGENT_FILE_XFER_STATUS: {
|
||||
VDAgentFileXferStatusMessage *msg = (VDAgentFileXferStatusMessage *) data;
|
||||
FIX_ENDIAN32(msg->result);
|
||||
// from client/server we don't expect any detail
|
||||
switch (msg->result) {
|
||||
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
|
||||
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
|
||||
sizeof(VDAgentFileXferStatusNotEnoughSpace)) {
|
||||
VDAgentFileXferStatusNotEnoughSpace *err =
|
||||
(VDAgentFileXferStatusNotEnoughSpace*) msg->data;
|
||||
FIX_ENDIAN64(err->disk_free_space);
|
||||
}
|
||||
break;
|
||||
case VD_AGENT_FILE_XFER_STATUS_ERROR:
|
||||
if (message_header->size >= sizeof(VDAgentFileXferStatusMessage) +
|
||||
sizeof(VDAgentFileXferStatusError)) {
|
||||
VDAgentFileXferStatusError *err =
|
||||
(VDAgentFileXferStatusError *) msg->data;
|
||||
FIX_ENDIAN32(err->error_code);
|
||||
}
|
||||
break;
|
||||
}
|
||||
break;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
static AgentCheckResult
|
||||
agent_message_graphics_device_info_check_from_le(const VDAgentMessage *message_header,
|
||||
uint8_t *data)
|
||||
{
|
||||
uint8_t *const end = data + message_header->size;
|
||||
uint32_unaligned_t *u32 = (uint32_unaligned_t *) data;
|
||||
FIX_ENDIAN32(u32->v);
|
||||
const uint32_t count = u32->v;
|
||||
data += 4;
|
||||
|
||||
for (size_t i = 0; i < count; ++i) {
|
||||
if ((size_t) (end - data) < sizeof(VDAgentDeviceDisplayInfo)) {
|
||||
return AGENT_CHECK_TRUNCATED;
|
||||
}
|
||||
uint32_from_le(data, sizeof(VDAgentDeviceDisplayInfo), 0);
|
||||
VDAgentDeviceDisplayInfo *info = (VDAgentDeviceDisplayInfo *) data;
|
||||
data += sizeof(VDAgentDeviceDisplayInfo);
|
||||
if (!info->device_address_len) {
|
||||
return AGENT_CHECK_INVALID_DATA;
|
||||
}
|
||||
if ((size_t) (end - data) < info->device_address_len) {
|
||||
return AGENT_CHECK_TRUNCATED;
|
||||
}
|
||||
info->device_address[info->device_address_len - 1] = 0;
|
||||
data += info->device_address_len;
|
||||
}
|
||||
return AGENT_CHECK_NO_ERROR;
|
||||
}
|
||||
|
||||
AgentCheckResult
|
||||
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
|
||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||
{
|
||||
AgentCheckResult res;
|
||||
|
||||
res = agent_message_check_size(message_header, capabilities, capabilities_size);
|
||||
if (res != AGENT_CHECK_NO_ERROR) {
|
||||
return res;
|
||||
}
|
||||
|
||||
switch (message_header->type) {
|
||||
case VD_AGENT_MOUSE_STATE:
|
||||
uint32_from_le(message, 3 * sizeof(uint32_t), 0);
|
||||
break;
|
||||
case VD_AGENT_REPLY:
|
||||
case VD_AGENT_DISPLAY_CONFIG:
|
||||
case VD_AGENT_MAX_CLIPBOARD:
|
||||
case VD_AGENT_ANNOUNCE_CAPABILITIES:
|
||||
uint32_from_le(message, message_header->size, 0);
|
||||
break;
|
||||
case VD_AGENT_MONITORS_CONFIG: {
|
||||
uint32_from_le(message, message_header->size, 0);
|
||||
VDAgentMonitorsConfig *vdata = (VDAgentMonitorsConfig*) message;
|
||||
const size_t max_monitors =
|
||||
(message_header->size - sizeof(*vdata)) / sizeof(vdata->monitors[0]);
|
||||
if (vdata->num_of_monitors > max_monitors) {
|
||||
return AGENT_CHECK_TRUNCATED;
|
||||
}
|
||||
break;
|
||||
}
|
||||
case VD_AGENT_CLIPBOARD:
|
||||
case VD_AGENT_CLIPBOARD_GRAB:
|
||||
case VD_AGENT_CLIPBOARD_REQUEST:
|
||||
case VD_AGENT_CLIPBOARD_RELEASE:
|
||||
agent_message_clipboard_from_le(message_header, message,
|
||||
capabilities, capabilities_size);
|
||||
break;
|
||||
case VD_AGENT_FILE_XFER_START:
|
||||
case VD_AGENT_FILE_XFER_STATUS:
|
||||
case VD_AGENT_FILE_XFER_DATA:
|
||||
agent_message_file_xfer_from_le(message_header, message);
|
||||
break;
|
||||
case VD_AGENT_CLIENT_DISCONNECTED:
|
||||
break;
|
||||
case VD_AGENT_GRAPHICS_DEVICE_INFO:
|
||||
return agent_message_graphics_device_info_check_from_le(message_header, message);
|
||||
|
||||
case VD_AGENT_AUDIO_VOLUME_SYNC: {
|
||||
VDAgentAudioVolumeSync *vdata = (VDAgentAudioVolumeSync *)message;
|
||||
const size_t max_channels =
|
||||
(message_header->size - sizeof(*vdata)) / sizeof(vdata->volume[0]);
|
||||
if (vdata->nchannels > max_channels) {
|
||||
return AGENT_CHECK_TRUNCATED;
|
||||
}
|
||||
uint16_from_le(message, message_header->size, sizeof(*vdata));
|
||||
break;
|
||||
}
|
||||
default:
|
||||
return AGENT_CHECK_UNKNOWN_MESSAGE;
|
||||
}
|
||||
return AGENT_CHECK_NO_ERROR;
|
||||
}
|
||||
|
||||
void
|
||||
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
|
||||
const uint32_t *capabilities, uint32_t capabilities_size)
|
||||
{
|
||||
if (*status_size < sizeof(status->common)) {
|
||||
*status_size = sizeof(status->common);
|
||||
}
|
||||
|
||||
// if there are details but no cap for detail remove it
|
||||
if (!VD_AGENT_HAS_CAPABILITY(capabilities, capabilities_size,
|
||||
VD_AGENT_CAP_FILE_XFER_DETAILED_ERRORS)) {
|
||||
*status_size = sizeof(status->common);
|
||||
|
||||
// if detail cap is not provided and error > threshold set to error
|
||||
if (status->common.result >= VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE) {
|
||||
status->common.result = VD_AGENT_FILE_XFER_STATUS_ERROR;
|
||||
}
|
||||
}
|
||||
|
||||
// fix endian
|
||||
switch (status->common.result) {
|
||||
case VD_AGENT_FILE_XFER_STATUS_NOT_ENOUGH_SPACE:
|
||||
FIX_ENDIAN64(status->not_enough_space.disk_free_space);
|
||||
break;
|
||||
case VD_AGENT_FILE_XFER_STATUS_ERROR:
|
||||
FIX_ENDIAN32(status->error.error_code);
|
||||
break;
|
||||
}
|
||||
// header should be done last
|
||||
FIX_ENDIAN32(status->common.id);
|
||||
FIX_ENDIAN32(status->common.result);
|
||||
}
|
||||
75
common/agent.h
Normal file
75
common/agent.h
Normal file
@ -0,0 +1,75 @@
|
||||
/* -*- Mode: C; c-basic-offset: 4; indent-tabs-mode: nil -*- */
|
||||
/*
|
||||
Copyright (C) 2020 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, see <http://www.gnu.org/licenses/>.
|
||||
*/
|
||||
#pragma once
|
||||
|
||||
#include <spice/macros.h>
|
||||
#include <spice/vd_agent.h>
|
||||
|
||||
SPICE_BEGIN_DECLS
|
||||
|
||||
#include <spice/start-packed.h>
|
||||
|
||||
/**
|
||||
* Structure to fill with transfer status.
|
||||
* Fill as much details as you can and call agent_prepare_filexfer_status
|
||||
* before sending to adjust for capabilities and endianness.
|
||||
* If any detail are filled the status_size passed to agent_prepare_filexfer_status
|
||||
* should be updated.
|
||||
*/
|
||||
typedef struct SPICE_ATTR_PACKED AgentFileXferStatusMessageFull {
|
||||
VDAgentFileXferStatusMessage common;
|
||||
union SPICE_ATTR_PACKED {
|
||||
VDAgentFileXferStatusNotEnoughSpace not_enough_space;
|
||||
VDAgentFileXferStatusError error;
|
||||
};
|
||||
} AgentFileXferStatusMessageFull;
|
||||
|
||||
#include <spice/end-packed.h>
|
||||
|
||||
/**
|
||||
* Prepare AgentFileXferStatusMessageFull to
|
||||
* be sent to network.
|
||||
* Avoid protocol incompatibilities and endian issues
|
||||
*/
|
||||
void
|
||||
agent_prepare_filexfer_status(AgentFileXferStatusMessageFull *status, size_t *status_size,
|
||||
const uint32_t *capabilities, uint32_t capabilities_size);
|
||||
|
||||
/**
|
||||
* Possible results checking a message.
|
||||
* Beside AGENT_CHECK_NO_ERROR all other conditions are errors.
|
||||
*/
|
||||
typedef enum AgentCheckResult {
|
||||
AGENT_CHECK_NO_ERROR,
|
||||
AGENT_CHECK_WRONG_PROTOCOL_VERSION,
|
||||
AGENT_CHECK_UNKNOWN_MESSAGE,
|
||||
AGENT_CHECK_INVALID_SIZE,
|
||||
AGENT_CHECK_TRUNCATED,
|
||||
AGENT_CHECK_INVALID_DATA,
|
||||
} AgentCheckResult;
|
||||
|
||||
/**
|
||||
* Check message from network and fix endianness
|
||||
* Returns AGENT_CHECK_NO_ERROR if message is valid.
|
||||
* message buffer size should be message_header->size.
|
||||
*/
|
||||
AgentCheckResult
|
||||
agent_check_message(const VDAgentMessage *message_header, uint8_t *message,
|
||||
const uint32_t *capabilities, uint32_t capabilities_size);
|
||||
|
||||
SPICE_END_DECLS
|
||||
@ -2,6 +2,8 @@
|
||||
# libspice-common
|
||||
#
|
||||
spice_common_sources = [
|
||||
'agent.c',
|
||||
'agent.h',
|
||||
'backtrace.c',
|
||||
'backtrace.h',
|
||||
'canvas_utils.c',
|
||||
|
||||
@ -51,7 +51,7 @@ AS_IF([test "x$enable_alignment_checks" = "xyes"],
|
||||
SPICE_CHECK_INSTRUMENTATION
|
||||
|
||||
# Checks for libraries
|
||||
PKG_CHECK_MODULES([PROTOCOL], [spice-protocol >= 0.12.12])
|
||||
PKG_CHECK_MODULES([PROTOCOL], [spice-protocol >= 0.14.2])
|
||||
|
||||
SPICE_CHECK_PYTHON_MODULES()
|
||||
|
||||
|
||||
@ -337,8 +337,8 @@ dnl The flags are necessary in order to make included header working
|
||||
AC_REQUIRE([SPICE_EXTRA_CHECKS])dnl
|
||||
AC_REQUIRE([SPICE_CHECK_INSTRUMENTATION])dnl
|
||||
dnl Get the required spice protocol version
|
||||
m4_define([SPICE_PROTOCOL_MIN_VER],m4_ifdef([SPICE_PROTOCOL_MIN_VER],SPICE_PROTOCOL_MIN_VER,[0.12.12]))dnl
|
||||
m4_define([SPICE_PROTOCOL_MIN_VER],m4_if(m4_version_compare(SPICE_PROTOCOL_MIN_VER,[0.12.12]),[1],SPICE_PROTOCOL_MIN_VER,[0.12.12]))dnl
|
||||
m4_define([SPICE_PROTOCOL_MIN_VER],m4_ifdef([SPICE_PROTOCOL_MIN_VER],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
|
||||
m4_define([SPICE_PROTOCOL_MIN_VER],m4_if(m4_version_compare(SPICE_PROTOCOL_MIN_VER,[0.14.2]),[1],SPICE_PROTOCOL_MIN_VER,[0.14.2]))dnl
|
||||
[SPICE_PROTOCOL_MIN_VER]=SPICE_PROTOCOL_MIN_VER
|
||||
m4_undefine([SPICE_PROTOCOL_MIN_VER])dnl
|
||||
PKG_CHECK_MODULES([SPICE_PROTOCOL], [spice-protocol >= $SPICE_PROTOCOL_MIN_VER])
|
||||
|
||||
@ -95,7 +95,7 @@ endif
|
||||
glib_version = '2.38'
|
||||
glib_version_info = '>= @0@'.format(glib_version)
|
||||
|
||||
spice_protocol_version = '0.12.12'
|
||||
spice_protocol_version = '0.14.2'
|
||||
|
||||
spice_protocol_version_req = get_option('spice-protocol-version')
|
||||
if spice_protocol_version_req.version_compare('> @0@'.format(spice_protocol_version))
|
||||
|
||||
Loading…
Reference in New Issue
Block a user