mirror of
https://github.com/Motorhead1991/qemu.git
synced 2025-12-11 16:00:50 -07:00
Misc VNC, I/O, Crypto & checkpatch changes
* Fix VNC tight encoding with 8/16-bpp formats with mixed endian server/client * Fix VNC non-tight encoding with mixed endian server/client * Drop built-in AES impl from non-TCG usage, requiring nettle/gcrypt/gnutls * Fix validation of SPDX-License-Identifier in new files * Mandate SPDX-License-Identifier in Rust source * Reject license boilerplate in new files * Add full control over TCP keep alive setting for sockets -----BEGIN PGP SIGNATURE----- iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmgu/EgACgkQvobrtBUQ T994FA/7BLeIHJqsV3/DtPKVqllzG2PJT/n85Owu/h39gqRsqHDssDQFPmgFsnzk UcvOSLd7RKQ5/tY5zLPh4JPpnloJ/jpj50hUK42wu8Q4U16PV/yUhQVVjEkVmX+z XepbEwgrEVuy4F62NnUJmbaT5PcayyS5FPREbrQ8zPzagMWTSqbR7EQ+PCTUkJdo LR4mvxoqWhGnaQzPAGlRtAfRfT6Jg3NaL4sLqLiexuhdloZLHC85SvE1usBg8x+M KP2BX1FeIILnN+1CXnZ9/vzUqiFaFLfzGwVMK9QYW0GW2Oo3uCcLloY+llbo6Pq/ tC8Po8AMIOojnrJm+TeS6V18QBNU5qqyHKGamZrSlBobZRgC7tOSljExoT5mnGrS V1nKNAz5FLz7LQ8jZpziPlPqr3WBqBRtV8SxJD+a0vh0/5YnTCbPC0Q6Q2N8cQDh Wra9QN10xD60tjsnRT/7Lp7gW/RyjT+uJHQkNxn6PZVbI/6Q1283YpbmVY55vcNe De47LPsmc6XnpJSmzmjt+VrWLob67IOo4JcttMrv7xWj08jb1TFUf7M0Mvdu2YBR 3C9MAt5sjmL9qHARToXr8RC3SCX9pMTZFYatHGAbRdRDi6ygFW1OQVJvxrOj00kN bavXjcDlTfRzgTnVRbqUbqSY0D9LZqSUDRxfQdEBGAzWgMksAuM= =X323 -----END PGP SIGNATURE----- Merge tag 'misc-next-pull-request' of https://gitlab.com/berrange/qemu into staging Misc VNC, I/O, Crypto & checkpatch changes * Fix VNC tight encoding with 8/16-bpp formats with mixed endian server/client * Fix VNC non-tight encoding with mixed endian server/client * Drop built-in AES impl from non-TCG usage, requiring nettle/gcrypt/gnutls * Fix validation of SPDX-License-Identifier in new files * Mandate SPDX-License-Identifier in Rust source * Reject license boilerplate in new files * Add full control over TCP keep alive setting for sockets # -----BEGIN PGP SIGNATURE----- # # iQIzBAABCAAdFiEE2vOm/bJrYpEtDo4/vobrtBUQT98FAmgu/EgACgkQvobrtBUQ # T994FA/7BLeIHJqsV3/DtPKVqllzG2PJT/n85Owu/h39gqRsqHDssDQFPmgFsnzk # UcvOSLd7RKQ5/tY5zLPh4JPpnloJ/jpj50hUK42wu8Q4U16PV/yUhQVVjEkVmX+z # XepbEwgrEVuy4F62NnUJmbaT5PcayyS5FPREbrQ8zPzagMWTSqbR7EQ+PCTUkJdo # LR4mvxoqWhGnaQzPAGlRtAfRfT6Jg3NaL4sLqLiexuhdloZLHC85SvE1usBg8x+M # KP2BX1FeIILnN+1CXnZ9/vzUqiFaFLfzGwVMK9QYW0GW2Oo3uCcLloY+llbo6Pq/ # tC8Po8AMIOojnrJm+TeS6V18QBNU5qqyHKGamZrSlBobZRgC7tOSljExoT5mnGrS # V1nKNAz5FLz7LQ8jZpziPlPqr3WBqBRtV8SxJD+a0vh0/5YnTCbPC0Q6Q2N8cQDh # Wra9QN10xD60tjsnRT/7Lp7gW/RyjT+uJHQkNxn6PZVbI/6Q1283YpbmVY55vcNe # De47LPsmc6XnpJSmzmjt+VrWLob67IOo4JcttMrv7xWj08jb1TFUf7M0Mvdu2YBR # 3C9MAt5sjmL9qHARToXr8RC3SCX9pMTZFYatHGAbRdRDi6ygFW1OQVJvxrOj00kN # bavXjcDlTfRzgTnVRbqUbqSY0D9LZqSUDRxfQdEBGAzWgMksAuM= # =X323 # -----END PGP SIGNATURE----- # gpg: Signature made Thu 22 May 2025 06:28:24 EDT # gpg: using RSA key DAF3A6FDB26B62912D0E8E3FBE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" [full] # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" [full] # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * tag 'misc-next-pull-request' of https://gitlab.com/berrange/qemu: (23 commits) scripts/checkpatch.pl: mandate SPDX tag for Rust src files util/qemu-sockets: Introduce inet socket options controlling TCP keep-alive util/qemu-sockets: Refactor inet_parse() to use QemuOpts util/qemu-sockets: Add support for keep-alive flag to passive sockets util/qemu-sockets: Refactor success and failure paths in inet_listen_saddr() util/qemu-sockets: Refactor setting client sockopts into a separate function io: Fix partial struct copy in qio_dns_resolver_lookup_sync_inet() scripts/checkpatch: reject license boilerplate on new files scripts/checkpatch: reimplement mandate for SPDX-License-Identifier scripts/checkpatch: use new hook for MAINTAINERS update check scripts/checkpatch: expand pattern for matching makefiles scripts/checkpatch: use new hook for file permissions check scripts/checkpatch: use new hook for ACPI test data check scripts/checkpatch: introduce tracking of file start/end scripts/checkpatch.pl: fix various indentation mistakes Revert "scripts: mandate that new files have SPDX-License-Identifier" crypto: fully drop built-in cipher provider tests: fix skipping cipher tests when AES is not available tests: skip legacy qcow2 encryption test if AES is not available tests: skip encrypted secret tests if AES is not available ... Signed-off-by: Stefan Hajnoczi <stefanha@redhat.com>
This commit is contained in:
commit
4589acc17a
19 changed files with 851 additions and 630 deletions
|
|
@ -1,303 +0,0 @@
|
|||
/*
|
||||
* QEMU Crypto cipher built-in algorithms
|
||||
*
|
||||
* Copyright (c) 2015 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 "crypto/aes.h"
|
||||
|
||||
typedef struct QCryptoCipherBuiltinAESContext QCryptoCipherBuiltinAESContext;
|
||||
struct QCryptoCipherBuiltinAESContext {
|
||||
AES_KEY enc;
|
||||
AES_KEY dec;
|
||||
};
|
||||
|
||||
typedef struct QCryptoCipherBuiltinAES QCryptoCipherBuiltinAES;
|
||||
struct QCryptoCipherBuiltinAES {
|
||||
QCryptoCipher base;
|
||||
QCryptoCipherBuiltinAESContext key;
|
||||
uint8_t iv[AES_BLOCK_SIZE];
|
||||
};
|
||||
|
||||
|
||||
static inline bool qcrypto_length_check(size_t len, size_t blocksize,
|
||||
Error **errp)
|
||||
{
|
||||
if (unlikely(len & (blocksize - 1))) {
|
||||
error_setg(errp, "Length %zu must be a multiple of block size %zu",
|
||||
len, blocksize);
|
||||
return false;
|
||||
}
|
||||
return true;
|
||||
}
|
||||
|
||||
static void qcrypto_cipher_ctx_free(QCryptoCipher *cipher)
|
||||
{
|
||||
g_free(cipher);
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_no_setiv(QCryptoCipher *cipher,
|
||||
const uint8_t *iv, size_t niv,
|
||||
Error **errp)
|
||||
{
|
||||
error_setg(errp, "Setting IV is not supported");
|
||||
return -1;
|
||||
}
|
||||
|
||||
static void do_aes_encrypt_ecb(const void *vctx,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *ctx = vctx;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
AES_encrypt(in, out, &ctx->enc);
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_aes_decrypt_ecb(const void *vctx,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in)
|
||||
{
|
||||
const QCryptoCipherBuiltinAESContext *ctx = vctx;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
AES_decrypt(in, out, &ctx->dec);
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
len -= AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_aes_encrypt_cbc(const AES_KEY *key,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
uint8_t *ivec)
|
||||
{
|
||||
uint8_t tmp[AES_BLOCK_SIZE];
|
||||
size_t n;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n) {
|
||||
tmp[n] = in[n] ^ ivec[n];
|
||||
}
|
||||
AES_encrypt(tmp, out, key);
|
||||
memcpy(ivec, out, AES_BLOCK_SIZE);
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static void do_aes_decrypt_cbc(const AES_KEY *key,
|
||||
size_t len,
|
||||
uint8_t *out,
|
||||
const uint8_t *in,
|
||||
uint8_t *ivec)
|
||||
{
|
||||
uint8_t tmp[AES_BLOCK_SIZE];
|
||||
size_t n;
|
||||
|
||||
/* We have already verified that len % AES_BLOCK_SIZE == 0. */
|
||||
while (len) {
|
||||
memcpy(tmp, in, AES_BLOCK_SIZE);
|
||||
AES_decrypt(in, out, key);
|
||||
for (n = 0; n < AES_BLOCK_SIZE; ++n) {
|
||||
out[n] ^= ivec[n];
|
||||
}
|
||||
memcpy(ivec, tmp, AES_BLOCK_SIZE);
|
||||
len -= AES_BLOCK_SIZE;
|
||||
in += AES_BLOCK_SIZE;
|
||||
out += AES_BLOCK_SIZE;
|
||||
}
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_encrypt_ecb(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_encrypt_ecb(&ctx->key, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_decrypt_ecb(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_decrypt_ecb(&ctx->key, len, out, in);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_encrypt_cbc(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_encrypt_cbc(&ctx->key.enc, len, out, in, ctx->iv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_decrypt_cbc(QCryptoCipher *cipher,
|
||||
const void *in, void *out,
|
||||
size_t len, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (!qcrypto_length_check(len, AES_BLOCK_SIZE, errp)) {
|
||||
return -1;
|
||||
}
|
||||
do_aes_decrypt_cbc(&ctx->key.dec, len, out, in, ctx->iv);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int qcrypto_cipher_aes_setiv(QCryptoCipher *cipher, const uint8_t *iv,
|
||||
size_t niv, Error **errp)
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx
|
||||
= container_of(cipher, QCryptoCipherBuiltinAES, base);
|
||||
|
||||
if (niv != AES_BLOCK_SIZE) {
|
||||
error_setg(errp, "IV must be %d bytes not %zu",
|
||||
AES_BLOCK_SIZE, niv);
|
||||
return -1;
|
||||
}
|
||||
|
||||
memcpy(ctx->iv, iv, AES_BLOCK_SIZE);
|
||||
return 0;
|
||||
}
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_ecb = {
|
||||
.cipher_encrypt = qcrypto_cipher_aes_encrypt_ecb,
|
||||
.cipher_decrypt = qcrypto_cipher_aes_decrypt_ecb,
|
||||
.cipher_setiv = qcrypto_cipher_no_setiv,
|
||||
.cipher_free = qcrypto_cipher_ctx_free,
|
||||
};
|
||||
|
||||
static const struct QCryptoCipherDriver qcrypto_cipher_aes_driver_cbc = {
|
||||
.cipher_encrypt = qcrypto_cipher_aes_encrypt_cbc,
|
||||
.cipher_decrypt = qcrypto_cipher_aes_decrypt_cbc,
|
||||
.cipher_setiv = qcrypto_cipher_aes_setiv,
|
||||
.cipher_free = qcrypto_cipher_ctx_free,
|
||||
};
|
||||
|
||||
bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
|
||||
QCryptoCipherMode mode)
|
||||
{
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALGO_AES_128:
|
||||
case QCRYPTO_CIPHER_ALGO_AES_192:
|
||||
case QCRYPTO_CIPHER_ALGO_AES_256:
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
return true;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
return false;
|
||||
}
|
||||
}
|
||||
|
||||
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
switch (alg) {
|
||||
case QCRYPTO_CIPHER_ALGO_AES_128:
|
||||
case QCRYPTO_CIPHER_ALGO_AES_192:
|
||||
case QCRYPTO_CIPHER_ALGO_AES_256:
|
||||
{
|
||||
QCryptoCipherBuiltinAES *ctx;
|
||||
const QCryptoCipherDriver *drv;
|
||||
|
||||
switch (mode) {
|
||||
case QCRYPTO_CIPHER_MODE_ECB:
|
||||
drv = &qcrypto_cipher_aes_driver_ecb;
|
||||
break;
|
||||
case QCRYPTO_CIPHER_MODE_CBC:
|
||||
drv = &qcrypto_cipher_aes_driver_cbc;
|
||||
break;
|
||||
default:
|
||||
goto bad_mode;
|
||||
}
|
||||
|
||||
ctx = g_new0(QCryptoCipherBuiltinAES, 1);
|
||||
ctx->base.driver = drv;
|
||||
|
||||
if (AES_set_encrypt_key(key, nkey * 8, &ctx->key.enc)) {
|
||||
error_setg(errp, "Failed to set encryption key");
|
||||
goto error;
|
||||
}
|
||||
if (AES_set_decrypt_key(key, nkey * 8, &ctx->key.dec)) {
|
||||
error_setg(errp, "Failed to set decryption key");
|
||||
goto error;
|
||||
}
|
||||
|
||||
return &ctx->base;
|
||||
|
||||
error:
|
||||
g_free(ctx);
|
||||
return NULL;
|
||||
}
|
||||
|
||||
default:
|
||||
error_setg(errp,
|
||||
"Unsupported cipher algorithm %s",
|
||||
QCryptoCipherAlgo_str(alg));
|
||||
return NULL;
|
||||
}
|
||||
|
||||
bad_mode:
|
||||
error_setg(errp, "Unsupported cipher mode %s",
|
||||
QCryptoCipherMode_str(mode));
|
||||
return NULL;
|
||||
}
|
||||
30
crypto/cipher-stub.c.inc
Normal file
30
crypto/cipher-stub.c.inc
Normal file
|
|
@ -0,0 +1,30 @@
|
|||
/*
|
||||
* SPDX-License-Identifier: GPL-2.0-or-later
|
||||
*
|
||||
* QEMU Crypto cipher impl stub
|
||||
*
|
||||
* Copyright (c) 2025 Red Hat, Inc.
|
||||
*
|
||||
*/
|
||||
|
||||
bool qcrypto_cipher_supports(QCryptoCipherAlgo alg,
|
||||
QCryptoCipherMode mode)
|
||||
{
|
||||
return false;
|
||||
}
|
||||
|
||||
static QCryptoCipher *qcrypto_cipher_ctx_new(QCryptoCipherAlgo alg,
|
||||
QCryptoCipherMode mode,
|
||||
const uint8_t *key,
|
||||
size_t nkey,
|
||||
Error **errp)
|
||||
{
|
||||
if (!qcrypto_cipher_validate_key_length(alg, mode, nkey, errp)) {
|
||||
return NULL;
|
||||
}
|
||||
|
||||
error_setg(errp,
|
||||
"Unsupported cipher algorithm %s, no crypto library enabled in build",
|
||||
QCryptoCipherAlgo_str(alg));
|
||||
return NULL;
|
||||
}
|
||||
|
|
@ -145,7 +145,7 @@ qcrypto_cipher_validate_key_length(QCryptoCipherAlgo alg,
|
|||
#elif defined CONFIG_GNUTLS_CRYPTO
|
||||
#include "cipher-gnutls.c.inc"
|
||||
#else
|
||||
#include "cipher-builtin.c.inc"
|
||||
#include "cipher-stub.c.inc"
|
||||
#endif
|
||||
|
||||
QCryptoCipher *qcrypto_cipher_new(QCryptoCipherAlgo alg,
|
||||
|
|
|
|||
|
|
@ -75,12 +75,12 @@ PixelFormat qemu_pixelformat_from_pixman(pixman_format_code_t format);
|
|||
pixman_format_code_t qemu_default_pixman_format(int bpp, bool native_endian);
|
||||
pixman_format_code_t qemu_drm_format_to_pixman(uint32_t drm_format);
|
||||
uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman);
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift);
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian);
|
||||
bool qemu_pixman_check_format(DisplayChangeListener *dcl,
|
||||
pixman_format_code_t format);
|
||||
|
||||
#ifdef CONFIG_PIXMAN
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf);
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian);
|
||||
pixman_image_t *qemu_pixman_linebuf_create(pixman_format_code_t format,
|
||||
int width);
|
||||
void qemu_pixman_linebuf_fill(pixman_image_t *linebuf, pixman_image_t *fb,
|
||||
|
|
|
|||
|
|
@ -111,22 +111,11 @@ static int qio_dns_resolver_lookup_sync_inet(QIODNSResolver *resolver,
|
|||
uaddr, INET6_ADDRSTRLEN, uport, 32,
|
||||
NI_NUMERICHOST | NI_NUMERICSERV);
|
||||
|
||||
newaddr->u.inet = (InetSocketAddress){
|
||||
.host = g_strdup(uaddr),
|
||||
.port = g_strdup(uport),
|
||||
.has_numeric = true,
|
||||
.numeric = true,
|
||||
.has_to = iaddr->has_to,
|
||||
.to = iaddr->to,
|
||||
.has_ipv4 = iaddr->has_ipv4,
|
||||
.ipv4 = iaddr->ipv4,
|
||||
.has_ipv6 = iaddr->has_ipv6,
|
||||
.ipv6 = iaddr->ipv6,
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
.has_mptcp = iaddr->has_mptcp,
|
||||
.mptcp = iaddr->mptcp,
|
||||
#endif
|
||||
};
|
||||
newaddr->u.inet = *iaddr;
|
||||
newaddr->u.inet.host = g_strdup(uaddr),
|
||||
newaddr->u.inet.port = g_strdup(uport),
|
||||
newaddr->u.inet.has_numeric = true,
|
||||
newaddr->u.inet.numeric = true,
|
||||
|
||||
(*addrs)[i] = newaddr;
|
||||
}
|
||||
|
|
|
|||
30
meson.build
30
meson.build
|
|
@ -2760,6 +2760,36 @@ if linux_io_uring.found()
|
|||
config_host_data.set('HAVE_IO_URING_PREP_WRITEV2',
|
||||
cc.has_header_symbol('liburing.h', 'io_uring_prep_writev2'))
|
||||
endif
|
||||
config_host_data.set('HAVE_TCP_KEEPCNT',
|
||||
cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPCNT') or
|
||||
cc.compiles('''
|
||||
#include <ws2tcpip.h>
|
||||
#ifndef TCP_KEEPCNT
|
||||
#error
|
||||
#endif
|
||||
int main(void) { return 0; }''',
|
||||
name: 'Win32 TCP_KEEPCNT'))
|
||||
# On Darwin TCP_KEEPIDLE is available under different name, TCP_KEEPALIVE.
|
||||
# https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172
|
||||
config_host_data.set('HAVE_TCP_KEEPIDLE',
|
||||
cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPIDLE') or
|
||||
cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPALIVE') or
|
||||
cc.compiles('''
|
||||
#include <ws2tcpip.h>
|
||||
#ifndef TCP_KEEPIDLE
|
||||
#error
|
||||
#endif
|
||||
int main(void) { return 0; }''',
|
||||
name: 'Win32 TCP_KEEPIDLE'))
|
||||
config_host_data.set('HAVE_TCP_KEEPINTVL',
|
||||
cc.has_header_symbol('netinet/tcp.h', 'TCP_KEEPINTVL') or
|
||||
cc.compiles('''
|
||||
#include <ws2tcpip.h>
|
||||
#ifndef TCP_KEEPINTVL
|
||||
#error
|
||||
#endif
|
||||
int main(void) { return 0; }''',
|
||||
name: 'Win32 TCP_KEEPINTVL'))
|
||||
|
||||
# has_member
|
||||
config_host_data.set('HAVE_SIGEV_NOTIFY_THREAD_ID',
|
||||
|
|
|
|||
|
|
@ -56,8 +56,24 @@
|
|||
# @ipv6: whether to accept IPv6 addresses, default try both IPv4 and
|
||||
# IPv6
|
||||
#
|
||||
# @keep-alive: enable keep-alive when connecting to this socket. Not
|
||||
# supported for passive sockets. (Since 4.2)
|
||||
# @keep-alive: enable keep-alive when connecting to/listening on this socket.
|
||||
# (Since 4.2, not supported for listening sockets until 10.1)
|
||||
#
|
||||
# @keep-alive-count: number of keep-alive packets sent before the connection is
|
||||
# closed. Only supported for TCP sockets on systems where TCP_KEEPCNT
|
||||
# socket option is defined (this includes Linux, Windows, macOS, FreeBSD,
|
||||
# but not OpenBSD). When set to 0, system setting is used. (Since 10.1)
|
||||
#
|
||||
# @keep-alive-idle: time in seconds the connection needs to be idle before
|
||||
# sending a keepalive packet. Only supported for TCP sockets on systems
|
||||
# where TCP_KEEPIDLE socket option is defined (this includes Linux,
|
||||
# Windows, macOS, FreeBSD, but not OpenBSD). When set to 0, system setting
|
||||
# is used. (Since 10.1)
|
||||
#
|
||||
# @keep-alive-interval: time in seconds between keep-alive packets. Only
|
||||
# supported for TCP sockets on systems where TCP_KEEPINTVL is defined (this
|
||||
# includes Linux, Windows, macOS, FreeBSD, but not OpenBSD). When set to
|
||||
# 0, system setting is used. (Since 10.1)
|
||||
#
|
||||
# @mptcp: enable multi-path TCP. (Since 6.1)
|
||||
#
|
||||
|
|
@ -71,6 +87,9 @@
|
|||
'*ipv4': 'bool',
|
||||
'*ipv6': 'bool',
|
||||
'*keep-alive': 'bool',
|
||||
'*keep-alive-count': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPCNT' },
|
||||
'*keep-alive-idle': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPIDLE' },
|
||||
'*keep-alive-interval': { 'type': 'uint32', 'if': 'HAVE_TCP_KEEPINTVL' },
|
||||
'*mptcp': { 'type': 'bool', 'if': 'HAVE_IPPROTO_MPTCP' } } }
|
||||
|
||||
##
|
||||
|
|
|
|||
|
|
@ -365,6 +365,18 @@ our @typeList = (
|
|||
qr{guintptr},
|
||||
);
|
||||
|
||||
# Match text found in common license boilerplate comments:
|
||||
# for new files the SPDX-License-Identifier line is sufficient.
|
||||
our @LICENSE_BOILERPLATE = (
|
||||
"licensed under the terms of the GNU GPL",
|
||||
"under the terms of the GNU General Public License",
|
||||
"under the terms of the GNU Lesser General Public",
|
||||
"Permission is hereby granted, free of charge",
|
||||
"GNU GPL, version 2 or later",
|
||||
"See the COPYING file"
|
||||
);
|
||||
our $LICENSE_BOILERPLATE_RE = join("|", @LICENSE_BOILERPLATE);
|
||||
|
||||
# Load common spelling mistakes and build regular expression list.
|
||||
my $misspellings;
|
||||
my %spelling_fix;
|
||||
|
|
@ -1330,29 +1342,6 @@ sub WARN {
|
|||
}
|
||||
}
|
||||
|
||||
# According to tests/qtest/bios-tables-test.c: do not
|
||||
# change expected file in the same commit with adding test
|
||||
sub checkfilename {
|
||||
my ($name, $acpi_testexpected, $acpi_nontestexpected) = @_;
|
||||
|
||||
# Note: shell script that rebuilds the expected files is in the same
|
||||
# directory as files themselves.
|
||||
# Note: allowed diff list can be changed both when changing expected
|
||||
# files and when changing tests.
|
||||
if ($name =~ m#^tests/data/acpi/# and not $name =~ m#^\.sh$#) {
|
||||
$$acpi_testexpected = $name;
|
||||
} elsif ($name !~ m#^tests/qtest/bios-tables-test-allowed-diff.h$#) {
|
||||
$$acpi_nontestexpected = $name;
|
||||
}
|
||||
if (defined $$acpi_testexpected and defined $$acpi_nontestexpected) {
|
||||
ERROR("Do not add expected files together with tests, " .
|
||||
"follow instructions in " .
|
||||
"tests/qtest/bios-tables-test.c: both " .
|
||||
$$acpi_testexpected . " and " .
|
||||
$$acpi_nontestexpected . " found\n");
|
||||
}
|
||||
}
|
||||
|
||||
sub checkspdx {
|
||||
my ($file, $expr) = @_;
|
||||
|
||||
|
|
@ -1417,6 +1406,118 @@ sub checkspdx {
|
|||
}
|
||||
}
|
||||
|
||||
# All three of the methods below take a 'file info' record
|
||||
# which is a hash ref containing
|
||||
#
|
||||
# 'isgit': 1 if an enhanced git diff or 0 for a plain diff
|
||||
# 'githeader': 1 if still parsing git patch header, 0 otherwise
|
||||
# 'linestart': line number of start of file diff
|
||||
# 'lineend': line number of end of file diff
|
||||
# 'filenew': the new filename
|
||||
# 'fileold': the old filename (same as 'new filename' except
|
||||
# for renames in git diffs)
|
||||
# 'action': one of 'modified' (always) or 'new' or 'deleted' or
|
||||
# 'renamed' (git diffs only)
|
||||
# 'mode': file mode for new/deleted files (git diffs only)
|
||||
# 'similarity': file similarity when renamed (git diffs only)
|
||||
# 'facts': hash ref for storing any metadata related to checks
|
||||
#
|
||||
|
||||
# Called at the end of each patch, with the list of
|
||||
# real filenames that were seen in the patch
|
||||
sub process_file_list {
|
||||
my @fileinfos = @_;
|
||||
|
||||
# According to tests/qtest/bios-tables-test.c: do not
|
||||
# change expected file in the same commit with adding test
|
||||
my @acpi_testexpected;
|
||||
my @acpi_nontestexpected;
|
||||
|
||||
foreach my $fileinfo (@fileinfos) {
|
||||
# Note: shell script that rebuilds the expected files is in
|
||||
# the same directory as files themselves.
|
||||
# Note: allowed diff list can be changed both when changing
|
||||
# expected files and when changing tests.
|
||||
if ($fileinfo->{filenew} =~ m#^tests/data/acpi/# &&
|
||||
$fileinfo->{filenew} !~ m#^\.sh$#) {
|
||||
push @acpi_testexpected, $fileinfo->{filenew};
|
||||
} elsif ($fileinfo->{filenew} !~
|
||||
m#^tests/qtest/bios-tables-test-allowed-diff.h$#) {
|
||||
push @acpi_nontestexpected, $fileinfo->{filenew};
|
||||
}
|
||||
}
|
||||
if (int(@acpi_testexpected) > 0 and int(@acpi_nontestexpected) > 0) {
|
||||
ERROR("Do not add expected files together with tests, " .
|
||||
"follow instructions in " .
|
||||
"tests/qtest/bios-tables-test.c. Files\n\n " .
|
||||
join("\n ", @acpi_testexpected) .
|
||||
"\n\nand\n\n " .
|
||||
join("\n ", @acpi_nontestexpected) .
|
||||
"\n\nfound in the same patch\n");
|
||||
}
|
||||
|
||||
my $sawmaintainers = 0;
|
||||
my @maybemaintainers;
|
||||
foreach my $fileinfo (@fileinfos) {
|
||||
if ($fileinfo->{action} ne "modified" &&
|
||||
$fileinfo->{filenew} !~ m#^tests/data/acpi/#) {
|
||||
push @maybemaintainers, $fileinfo->{filenew};
|
||||
}
|
||||
if ($fileinfo->{filenew} eq "MAINTAINERS") {
|
||||
$sawmaintainers = 1;
|
||||
}
|
||||
}
|
||||
|
||||
# If we don't see a MAINTAINERS update, prod the user to check
|
||||
if (int(@maybemaintainers) > 0 && !$sawmaintainers) {
|
||||
WARN("added, moved or deleted file(s):\n\n " .
|
||||
join("\n ", @maybemaintainers) .
|
||||
"\n\nDoes MAINTAINERS need updating?\n");
|
||||
}
|
||||
}
|
||||
|
||||
# Called at the start of processing a diff hunk for a file
|
||||
sub process_start_of_file {
|
||||
my $fileinfo = shift;
|
||||
|
||||
# Check for incorrect file permissions
|
||||
if ($fileinfo->{action} eq "new" && ($fileinfo->{mode} & 0111)) {
|
||||
my $permhere = $fileinfo->{linestart} . "FILE: " .
|
||||
$fileinfo->{filenew} . "\n";
|
||||
if ($fileinfo->{filenew} =~
|
||||
/(\bMakefile.*|\.(c|cc|cpp|h|mak|s|S))$/) {
|
||||
ERROR("do not set execute permissions for source " .
|
||||
"files\n" . $permhere);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
# Called at the end of processing a diff hunk for a file
|
||||
sub process_end_of_file {
|
||||
my $fileinfo = shift;
|
||||
|
||||
if ($fileinfo->{action} eq "new" &&
|
||||
!exists $fileinfo->{facts}->{sawspdx}) {
|
||||
if ($fileinfo->{filenew} =~
|
||||
/(\.(c|h|py|pl|sh|json|inc|rs)|Makefile.*)$/) {
|
||||
# source code files MUST have SPDX license declared
|
||||
ERROR("New file '" . $fileinfo->{filenew} .
|
||||
"' requires 'SPDX-License-Identifier'");
|
||||
} else {
|
||||
# Other files MAY have SPDX license if appropriate
|
||||
WARN("Does new file '" . $fileinfo->{filenew} .
|
||||
"' need 'SPDX-License-Identifier'?");
|
||||
}
|
||||
}
|
||||
if ($fileinfo->{action} eq "new" &&
|
||||
exists $fileinfo->{facts}->{sawboilerplate}) {
|
||||
ERROR("New file '" . $fileinfo->{filenew} . "' must " .
|
||||
"not have license boilerplate header text, only " .
|
||||
"the SPDX-License-Identifier, unless this file was " .
|
||||
"copied from existing code already having such text.");
|
||||
}
|
||||
}
|
||||
|
||||
sub process {
|
||||
my $filename = shift;
|
||||
|
||||
|
|
@ -1437,13 +1538,10 @@ sub process {
|
|||
|
||||
my $in_header_lines = $file ? 0 : 1;
|
||||
my $in_commit_log = 0; #Scanning lines before patch
|
||||
my $reported_maintainer_file = 0;
|
||||
my $reported_mixing_imported_file = 0;
|
||||
my $in_imported_file = 0;
|
||||
my $in_no_imported_file = 0;
|
||||
my $non_utf8_charset = 0;
|
||||
my $expect_spdx = 0;
|
||||
my $expect_spdx_file;
|
||||
|
||||
our @report = ();
|
||||
our $cnt_lines = 0;
|
||||
|
|
@ -1455,7 +1553,10 @@ sub process {
|
|||
my $realfile = '';
|
||||
my $realline = 0;
|
||||
my $realcnt = 0;
|
||||
my $fileinfo;
|
||||
my @fileinfolist;
|
||||
my $here = '';
|
||||
my $oldhere = '';
|
||||
my $in_comment = 0;
|
||||
my $comment_edge = 0;
|
||||
my $first_line = 0;
|
||||
|
|
@ -1468,9 +1569,6 @@ sub process {
|
|||
my %suppress_whiletrailers;
|
||||
my %suppress_export;
|
||||
|
||||
my $acpi_testexpected;
|
||||
my $acpi_nontestexpected;
|
||||
|
||||
# Pre-scan the patch sanitizing the lines.
|
||||
|
||||
sanitise_line_reset();
|
||||
|
|
@ -1593,18 +1691,54 @@ sub process {
|
|||
$prefix = "$filename:$realline: " if ($emacs && $file);
|
||||
$prefix = "$filename:$linenr: " if ($emacs && !$file);
|
||||
|
||||
$oldhere = $here;
|
||||
$here = "#$linenr: " if (!$file);
|
||||
$here = "#$realline: " if ($file);
|
||||
|
||||
# extract the filename as it passes
|
||||
if ($line =~ /^diff --git.*?(\S+)$/) {
|
||||
$realfile = $1;
|
||||
$realfile =~ s@^([^/]*)/@@ if (!$file);
|
||||
checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected);
|
||||
if ($line =~ /^diff --git\s+(\S+)\s+(\S+)$/) {
|
||||
my $fileold = $1;
|
||||
my $filenew = $2;
|
||||
|
||||
if (defined $fileinfo) {
|
||||
$fileinfo->{lineend} = $oldhere;
|
||||
process_end_of_file($fileinfo)
|
||||
}
|
||||
$fileold =~ s@^([^/]*)/@@ if (!$file);
|
||||
$filenew =~ s@^([^/]*)/@@ if (!$file);
|
||||
$realfile = $filenew;
|
||||
|
||||
$fileinfo = {
|
||||
"isgit" => 1,
|
||||
"githeader" => 1,
|
||||
"linestart" => $here,
|
||||
"lineend" => 0,
|
||||
"fileold" => $fileold,
|
||||
"filenew" => $filenew,
|
||||
"action" => "modified",
|
||||
"mode" => 0,
|
||||
"similarity" => 0,
|
||||
"facts" => {},
|
||||
};
|
||||
push @fileinfolist, $fileinfo;
|
||||
} elsif (defined $fileinfo && $fileinfo->{githeader} &&
|
||||
$line =~ /^(new|deleted) (?:file )?mode\s+([0-7]+)$/) {
|
||||
$fileinfo->{action} = $1;
|
||||
$fileinfo->{mode} = oct($2);
|
||||
} elsif (defined $fileinfo && $fileinfo->{githeader} &&
|
||||
$line =~ /^similarity index (\d+)%/) {
|
||||
$fileinfo->{similarity} = int($1);
|
||||
} elsif (defined $fileinfo && $fileinfo->{githeader} &&
|
||||
$line =~ /^rename (from|to) [\w\/\.\-]+\s*$/) {
|
||||
$fileinfo->{action} = "renamed";
|
||||
# For a no-change rename, we'll never have any "+++..."
|
||||
# lines, so trigger actions now
|
||||
if ($1 eq "to" && $fileinfo->{similarity} == 100) {
|
||||
process_start_of_file($fileinfo);
|
||||
}
|
||||
} elsif ($line =~ /^\+\+\+\s+(\S+)/) {
|
||||
$realfile = $1;
|
||||
$realfile =~ s@^([^/]*)/@@ if (!$file);
|
||||
checkfilename($realfile, \$acpi_testexpected, \$acpi_nontestexpected);
|
||||
|
||||
$p1_prefix = $1;
|
||||
if (!$file && $tree && $p1_prefix ne '' &&
|
||||
|
|
@ -1612,6 +1746,30 @@ sub process {
|
|||
WARN("patch prefix '$p1_prefix' exists, appears to be a -p0 patch\n");
|
||||
}
|
||||
|
||||
if (defined $fileinfo && !$fileinfo->{isgit}) {
|
||||
$fileinfo->{lineend} = $oldhere;
|
||||
process_end_of_file($fileinfo);
|
||||
}
|
||||
|
||||
if (!defined $fileinfo || !$fileinfo->{isgit}) {
|
||||
$fileinfo = {
|
||||
"isgit" => 0,
|
||||
"githeader" => 0,
|
||||
"linestart" => $here,
|
||||
"lineend" => 0,
|
||||
"fileold" => $realfile,
|
||||
"filenew" => $realfile,
|
||||
"action" => "modified",
|
||||
"mode" => 0,
|
||||
"similarity" => 0,
|
||||
"facts" => {},
|
||||
};
|
||||
push @fileinfolist, $fileinfo;
|
||||
} else {
|
||||
$fileinfo->{githeader} = 0;
|
||||
}
|
||||
process_start_of_file($fileinfo);
|
||||
|
||||
next;
|
||||
}
|
||||
|
||||
|
|
@ -1623,14 +1781,6 @@ sub process {
|
|||
|
||||
$cnt_lines++ if ($realcnt != 0);
|
||||
|
||||
# Check for incorrect file permissions
|
||||
if ($line =~ /^new (file )?mode.*[7531]\d{0,2}$/) {
|
||||
my $permhere = $here . "FILE: $realfile\n";
|
||||
if ($realfile =~ /(\bMakefile(?:\.objs)?|\.c|\.cc|\.cpp|\.h|\.mak|\.[sS])$/) {
|
||||
ERROR("do not set execute permissions for source files\n" . $permhere);
|
||||
}
|
||||
}
|
||||
|
||||
# Only allow Python 3 interpreter
|
||||
if ($realline == 1 &&
|
||||
$line =~ /^\+#!\ *\/usr\/bin\/(?:env )?python$/) {
|
||||
|
|
@ -1662,68 +1812,27 @@ sub process {
|
|||
}
|
||||
}
|
||||
|
||||
# Check if MAINTAINERS is being updated. If so, there's probably no need to
|
||||
# emit the "does MAINTAINERS need updating?" message on file add/move/delete
|
||||
if ($line =~ /^\s*MAINTAINERS\s*\|/) {
|
||||
$reported_maintainer_file = 1;
|
||||
}
|
||||
|
||||
# Check for added, moved or deleted files
|
||||
if (!$reported_maintainer_file && !$in_commit_log &&
|
||||
($line =~ /^(?:new|deleted) file mode\s*\d+\s*$/ ||
|
||||
$line =~ /^rename (?:from|to) [\w\/\.\-]+\s*$/ ||
|
||||
($line =~ /\{\s*([\w\/\.\-]*)\s*\=\>\s*([\w\/\.\-]*)\s*\}/ &&
|
||||
(defined($1) || defined($2)))) &&
|
||||
!(($realfile ne '') &&
|
||||
defined($acpi_testexpected) &&
|
||||
($realfile eq $acpi_testexpected))) {
|
||||
$reported_maintainer_file = 1;
|
||||
WARN("added, moved or deleted file(s), does MAINTAINERS need updating?\n" . $herecurr);
|
||||
}
|
||||
|
||||
# All new files should have a SPDX-License-Identifier tag
|
||||
if ($line =~ /^new file mode\s*\d+\s*$/) {
|
||||
if ($expect_spdx) {
|
||||
if ($expect_spdx_file =~
|
||||
/\.(c|h|py|pl|sh|json|inc|Makefile)$/) {
|
||||
# source code files MUST have SPDX license declared
|
||||
ERROR("New file '$expect_spdx_file' requires " .
|
||||
"'SPDX-License-Identifier'");
|
||||
} else {
|
||||
# Other files MAY have SPDX license if appropriate
|
||||
WARN("Does new file '$expect_spdx_file' need " .
|
||||
"'SPDX-License-Identifier'?");
|
||||
}
|
||||
}
|
||||
$expect_spdx = 1;
|
||||
$expect_spdx_file = undef;
|
||||
} elsif ($expect_spdx) {
|
||||
$expect_spdx_file = $realfile unless
|
||||
defined $expect_spdx_file;
|
||||
|
||||
# SPDX tags may occurr in comments which were
|
||||
# stripped from '$line', so use '$rawline'
|
||||
if ($rawline =~ /SPDX-License-Identifier/) {
|
||||
$expect_spdx = 0;
|
||||
$expect_spdx_file = undef;
|
||||
}
|
||||
}
|
||||
|
||||
# Check SPDX-License-Identifier references a permitted license
|
||||
if ($rawline =~ m,SPDX-License-Identifier: (.*?)(\*/)?\s*$,) {
|
||||
&checkspdx($realfile, $1);
|
||||
$fileinfo->{facts}->{sawspdx} = 1;
|
||||
&checkspdx($realfile, $1);
|
||||
}
|
||||
|
||||
if ($rawline =~ /$LICENSE_BOILERPLATE_RE/) {
|
||||
$fileinfo->{facts}->{sawboilerplate} = 1;
|
||||
}
|
||||
|
||||
if ($rawline =~ m,(SPDX-[a-zA-Z0-9-_]+):,) {
|
||||
my $tag = $1;
|
||||
my @permitted = qw(
|
||||
SPDX-License-Identifier
|
||||
);
|
||||
my $tag = $1;
|
||||
my @permitted = qw(
|
||||
SPDX-License-Identifier
|
||||
);
|
||||
|
||||
unless (grep { /^$tag$/ } @permitted) {
|
||||
ERROR("Tag $tag not permitted in QEMU code, valid " .
|
||||
"choices are: " . join(", ", @permitted));
|
||||
}
|
||||
unless (grep { /^$tag$/ } @permitted) {
|
||||
ERROR("Tag $tag not permitted in QEMU code, " .
|
||||
"valid choices are: " .
|
||||
join(", ", @permitted));
|
||||
}
|
||||
}
|
||||
|
||||
# Check for wrappage within a valid hunk of the file
|
||||
|
|
@ -2304,7 +2413,7 @@ sub process {
|
|||
|
||||
# missing space after union, struct or enum definition
|
||||
if ($line =~ /^.\s*(?:typedef\s+)?(enum|union|struct)(?:\s+$Ident)?(?:\s+$Ident)?[=\{]/) {
|
||||
ERROR("missing space after $1 definition\n" . $herecurr);
|
||||
ERROR("missing space after $1 definition\n" . $herecurr);
|
||||
}
|
||||
|
||||
# check for spacing round square brackets; allowed:
|
||||
|
|
@ -2599,7 +2708,7 @@ sub process {
|
|||
|
||||
if ($line =~ /^.\s*(Q(?:S?LIST|SIMPLEQ|TAILQ)_HEAD)\s*\(\s*[^,]/ &&
|
||||
$line !~ /^.typedef/) {
|
||||
ERROR("named $1 should be typedefed separately\n" . $herecurr);
|
||||
ERROR("named $1 should be typedefed separately\n" . $herecurr);
|
||||
}
|
||||
|
||||
# Need a space before open parenthesis after if, while etc
|
||||
|
|
@ -3148,48 +3257,50 @@ sub process {
|
|||
|
||||
# Qemu error function tests
|
||||
|
||||
# Find newlines in error messages
|
||||
my $qemu_error_funcs = qr{error_setg|
|
||||
error_setg_errno|
|
||||
error_setg_win32|
|
||||
error_setg_file_open|
|
||||
error_set|
|
||||
error_prepend|
|
||||
warn_reportf_err|
|
||||
error_reportf_err|
|
||||
error_vreport|
|
||||
warn_vreport|
|
||||
info_vreport|
|
||||
error_report|
|
||||
warn_report|
|
||||
info_report|
|
||||
g_test_message}x;
|
||||
# Find newlines in error messages
|
||||
my $qemu_error_funcs = qr{error_setg|
|
||||
error_setg_errno|
|
||||
error_setg_win32|
|
||||
error_setg_file_open|
|
||||
error_set|
|
||||
error_prepend|
|
||||
warn_reportf_err|
|
||||
error_reportf_err|
|
||||
error_vreport|
|
||||
warn_vreport|
|
||||
info_vreport|
|
||||
error_report|
|
||||
warn_report|
|
||||
info_report|
|
||||
g_test_message}x;
|
||||
|
||||
if ($rawline =~ /\b(?:$qemu_error_funcs)\s*\(.*\".*\\n/) {
|
||||
ERROR("Error messages should not contain newlines\n" . $herecurr);
|
||||
}
|
||||
|
||||
# Continue checking for error messages that contains newlines. This
|
||||
# check handles cases where string literals are spread over multiple lines.
|
||||
# Example:
|
||||
# error_report("Error msg line #1"
|
||||
# "Error msg line #2\n");
|
||||
my $quoted_newline_regex = qr{\+\s*\".*\\n.*\"};
|
||||
my $continued_str_literal = qr{\+\s*\".*\"};
|
||||
|
||||
if ($rawline =~ /$quoted_newline_regex/) {
|
||||
# Backtrack to first line that does not contain only a quoted literal
|
||||
# and assume that it is the start of the statement.
|
||||
my $i = $linenr - 2;
|
||||
|
||||
while (($i >= 0) & $rawlines[$i] =~ /$continued_str_literal/) {
|
||||
$i--;
|
||||
}
|
||||
|
||||
if ($rawlines[$i] =~ /\b(?:$qemu_error_funcs)\s*\(/) {
|
||||
if ($rawline =~ /\b(?:$qemu_error_funcs)\s*\(.*\".*\\n/) {
|
||||
ERROR("Error messages should not contain newlines\n" . $herecurr);
|
||||
}
|
||||
}
|
||||
|
||||
# Continue checking for error messages that contains newlines.
|
||||
# This check handles cases where string literals are spread
|
||||
# over multiple lines.
|
||||
# Example:
|
||||
# error_report("Error msg line #1"
|
||||
# "Error msg line #2\n");
|
||||
my $quoted_newline_regex = qr{\+\s*\".*\\n.*\"};
|
||||
my $continued_str_literal = qr{\+\s*\".*\"};
|
||||
|
||||
if ($rawline =~ /$quoted_newline_regex/) {
|
||||
# Backtrack to first line that does not contain only
|
||||
# a quoted literal and assume that it is the start
|
||||
# of the statement.
|
||||
my $i = $linenr - 2;
|
||||
|
||||
while (($i >= 0) & $rawlines[$i] =~ /$continued_str_literal/) {
|
||||
$i--;
|
||||
}
|
||||
|
||||
if ($rawlines[$i] =~ /\b(?:$qemu_error_funcs)\s*\(/) {
|
||||
ERROR("Error messages should not contain newlines\n" . $herecurr);
|
||||
}
|
||||
}
|
||||
|
||||
# check for non-portable libc calls that have portable alternatives in QEMU
|
||||
if ($line =~ /\bffs\(/) {
|
||||
|
|
@ -3243,6 +3354,11 @@ sub process {
|
|||
}
|
||||
}
|
||||
|
||||
if (defined $fileinfo) {
|
||||
process_end_of_file($fileinfo);
|
||||
}
|
||||
process_file_list(@fileinfolist);
|
||||
|
||||
if ($is_patch && $chk_signoff && $signoff == 0) {
|
||||
ERROR("Missing Signed-off-by: line(s)\n");
|
||||
}
|
||||
|
|
|
|||
|
|
@ -574,6 +574,13 @@ int main(int argc, char **argv)
|
|||
for (i = 0; i < G_N_ELEMENTS(test_data); i++) {
|
||||
if (test_data[i].open_opts->format == QCRYPTO_BLOCK_FORMAT_LUKS &&
|
||||
!qcrypto_hash_supports(test_data[i].hash_alg)) {
|
||||
g_printerr("# skip unsupported %s\n",
|
||||
QCryptoHashAlgo_str(test_data[i].hash_alg));
|
||||
continue;
|
||||
}
|
||||
if (!qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC)) {
|
||||
g_printerr("# skip unsupported aes-128:cbc\n");
|
||||
continue;
|
||||
}
|
||||
if (!test_data[i].slow ||
|
||||
|
|
|
|||
|
|
@ -828,11 +828,16 @@ int main(int argc, char **argv)
|
|||
}
|
||||
}
|
||||
|
||||
g_test_add_func("/crypto/cipher/null-iv",
|
||||
test_cipher_null_iv);
|
||||
if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_256,
|
||||
QCRYPTO_CIPHER_MODE_CBC)) {
|
||||
g_test_add_func("/crypto/cipher/null-iv",
|
||||
test_cipher_null_iv);
|
||||
|
||||
g_test_add_func("/crypto/cipher/short-plaintext",
|
||||
test_cipher_short_plaintext);
|
||||
g_test_add_func("/crypto/cipher/short-plaintext",
|
||||
test_cipher_short_plaintext);
|
||||
} else {
|
||||
g_printerr("# skip unsupported aes-256:cbc\n");
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -22,6 +22,7 @@
|
|||
|
||||
#include "crypto/init.h"
|
||||
#include "crypto/secret.h"
|
||||
#include "crypto/cipher.h"
|
||||
#include "qapi/error.h"
|
||||
#include "qemu/module.h"
|
||||
#if defined(CONFIG_KEYUTILS) && defined(CONFIG_SECRET_KEYRING)
|
||||
|
|
@ -597,18 +598,21 @@ int main(int argc, char **argv)
|
|||
g_test_add_func("/crypto/secret/conv/utf8/base64",
|
||||
test_secret_conv_utf8_base64);
|
||||
|
||||
g_test_add_func("/crypto/secret/crypt/raw",
|
||||
test_secret_crypt_raw);
|
||||
g_test_add_func("/crypto/secret/crypt/base64",
|
||||
test_secret_crypt_base64);
|
||||
g_test_add_func("/crypto/secret/crypt/shortkey",
|
||||
test_secret_crypt_short_key);
|
||||
g_test_add_func("/crypto/secret/crypt/shortiv",
|
||||
test_secret_crypt_short_iv);
|
||||
g_test_add_func("/crypto/secret/crypt/missingiv",
|
||||
test_secret_crypt_missing_iv);
|
||||
g_test_add_func("/crypto/secret/crypt/badiv",
|
||||
test_secret_crypt_bad_iv);
|
||||
if (qcrypto_cipher_supports(QCRYPTO_CIPHER_ALGO_AES_128,
|
||||
QCRYPTO_CIPHER_MODE_CBC)) {
|
||||
g_test_add_func("/crypto/secret/crypt/raw",
|
||||
test_secret_crypt_raw);
|
||||
g_test_add_func("/crypto/secret/crypt/base64",
|
||||
test_secret_crypt_base64);
|
||||
g_test_add_func("/crypto/secret/crypt/shortkey",
|
||||
test_secret_crypt_short_key);
|
||||
g_test_add_func("/crypto/secret/crypt/shortiv",
|
||||
test_secret_crypt_short_iv);
|
||||
g_test_add_func("/crypto/secret/crypt/missingiv",
|
||||
test_secret_crypt_missing_iv);
|
||||
g_test_add_func("/crypto/secret/crypt/badiv",
|
||||
test_secret_crypt_bad_iv);
|
||||
}
|
||||
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -332,6 +332,216 @@ static void test_socket_unix_abstract(void)
|
|||
|
||||
#endif /* CONFIG_LINUX */
|
||||
|
||||
static void inet_parse_test_helper(const char *str,
|
||||
InetSocketAddress *exp_addr, bool success)
|
||||
{
|
||||
InetSocketAddress addr;
|
||||
Error *error = NULL;
|
||||
|
||||
int rc = inet_parse(&addr, str, &error);
|
||||
|
||||
if (success) {
|
||||
g_assert_cmpint(rc, ==, 0);
|
||||
} else {
|
||||
g_assert_cmpint(rc, <, 0);
|
||||
}
|
||||
if (exp_addr != NULL) {
|
||||
g_assert_cmpstr(addr.host, ==, exp_addr->host);
|
||||
g_assert_cmpstr(addr.port, ==, exp_addr->port);
|
||||
/* Own members: */
|
||||
g_assert_cmpint(addr.has_numeric, ==, exp_addr->has_numeric);
|
||||
g_assert_cmpint(addr.numeric, ==, exp_addr->numeric);
|
||||
g_assert_cmpint(addr.has_to, ==, exp_addr->has_to);
|
||||
g_assert_cmpint(addr.to, ==, exp_addr->to);
|
||||
g_assert_cmpint(addr.has_ipv4, ==, exp_addr->has_ipv4);
|
||||
g_assert_cmpint(addr.ipv4, ==, exp_addr->ipv4);
|
||||
g_assert_cmpint(addr.has_ipv6, ==, exp_addr->has_ipv6);
|
||||
g_assert_cmpint(addr.ipv6, ==, exp_addr->ipv6);
|
||||
g_assert_cmpint(addr.has_keep_alive, ==, exp_addr->has_keep_alive);
|
||||
g_assert_cmpint(addr.keep_alive, ==, exp_addr->keep_alive);
|
||||
#ifdef HAVE_TCP_KEEPCNT
|
||||
g_assert_cmpint(addr.has_keep_alive_count, ==,
|
||||
exp_addr->has_keep_alive_count);
|
||||
g_assert_cmpint(addr.keep_alive_count, ==,
|
||||
exp_addr->keep_alive_count);
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPIDLE
|
||||
g_assert_cmpint(addr.has_keep_alive_idle, ==,
|
||||
exp_addr->has_keep_alive_idle);
|
||||
g_assert_cmpint(addr.keep_alive_idle, ==,
|
||||
exp_addr->keep_alive_idle);
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPINTVL
|
||||
g_assert_cmpint(addr.has_keep_alive_interval, ==,
|
||||
exp_addr->has_keep_alive_interval);
|
||||
g_assert_cmpint(addr.keep_alive_interval, ==,
|
||||
exp_addr->keep_alive_interval);
|
||||
#endif
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
g_assert_cmpint(addr.has_mptcp, ==, exp_addr->has_mptcp);
|
||||
g_assert_cmpint(addr.mptcp, ==, exp_addr->mptcp);
|
||||
#endif
|
||||
}
|
||||
|
||||
g_free(addr.host);
|
||||
g_free(addr.port);
|
||||
}
|
||||
|
||||
static void test_inet_parse_nohost_good(void)
|
||||
{
|
||||
char host[] = "";
|
||||
char port[] = "5000";
|
||||
InetSocketAddress exp_addr = {
|
||||
.host = host,
|
||||
.port = port,
|
||||
};
|
||||
inet_parse_test_helper(":5000", &exp_addr, true);
|
||||
}
|
||||
|
||||
static void test_inet_parse_empty_bad(void)
|
||||
{
|
||||
inet_parse_test_helper("", NULL, false);
|
||||
}
|
||||
|
||||
static void test_inet_parse_only_colon_bad(void)
|
||||
{
|
||||
inet_parse_test_helper(":", NULL, false);
|
||||
}
|
||||
|
||||
static void test_inet_parse_ipv4_good(void)
|
||||
{
|
||||
char host[] = "127.0.0.1";
|
||||
char port[] = "5000";
|
||||
InetSocketAddress exp_addr = {
|
||||
.host = host,
|
||||
.port = port,
|
||||
};
|
||||
inet_parse_test_helper("127.0.0.1:5000", &exp_addr, true);
|
||||
}
|
||||
|
||||
static void test_inet_parse_ipv4_noport_bad(void)
|
||||
{
|
||||
inet_parse_test_helper("127.0.0.1", NULL, false);
|
||||
}
|
||||
|
||||
static void test_inet_parse_ipv6_good(void)
|
||||
{
|
||||
char host[] = "::1";
|
||||
char port[] = "5000";
|
||||
InetSocketAddress exp_addr = {
|
||||
.host = host,
|
||||
.port = port,
|
||||
};
|
||||
inet_parse_test_helper("[::1]:5000", &exp_addr, true);
|
||||
}
|
||||
|
||||
static void test_inet_parse_ipv6_noend_bad(void)
|
||||
{
|
||||
inet_parse_test_helper("[::1", NULL, false);
|
||||
}
|
||||
|
||||
static void test_inet_parse_ipv6_noport_bad(void)
|
||||
{
|
||||
inet_parse_test_helper("[::1]:", NULL, false);
|
||||
}
|
||||
|
||||
static void test_inet_parse_ipv6_empty_bad(void)
|
||||
{
|
||||
inet_parse_test_helper("[]:5000", NULL, false);
|
||||
}
|
||||
|
||||
static void test_inet_parse_hostname_good(void)
|
||||
{
|
||||
char host[] = "localhost";
|
||||
char port[] = "5000";
|
||||
InetSocketAddress exp_addr = {
|
||||
.host = host,
|
||||
.port = port,
|
||||
};
|
||||
inet_parse_test_helper("localhost:5000", &exp_addr, true);
|
||||
}
|
||||
|
||||
static void test_inet_parse_all_options_good(void)
|
||||
{
|
||||
char host[] = "::1";
|
||||
char port[] = "5000";
|
||||
InetSocketAddress exp_addr = {
|
||||
.host = host,
|
||||
.port = port,
|
||||
.has_numeric = true,
|
||||
.numeric = true,
|
||||
.has_to = true,
|
||||
.to = 5006,
|
||||
.has_ipv4 = true,
|
||||
.ipv4 = false,
|
||||
.has_ipv6 = true,
|
||||
.ipv6 = true,
|
||||
.has_keep_alive = true,
|
||||
.keep_alive = true,
|
||||
#ifdef HAVE_TCP_KEEPCNT
|
||||
.has_keep_alive_count = true,
|
||||
.keep_alive_count = 10,
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPIDLE
|
||||
.has_keep_alive_idle = true,
|
||||
.keep_alive_idle = 60,
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPINTVL
|
||||
.has_keep_alive_interval = true,
|
||||
.keep_alive_interval = 30,
|
||||
#endif
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
.has_mptcp = true,
|
||||
.mptcp = false,
|
||||
#endif
|
||||
};
|
||||
inet_parse_test_helper(
|
||||
"[::1]:5000,numeric=on,to=5006,ipv4=off,ipv6=on,keep-alive=on"
|
||||
#ifdef HAVE_TCP_KEEPCNT
|
||||
",keep-alive-count=10"
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPIDLE
|
||||
",keep-alive-idle=60"
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPINTVL
|
||||
",keep-alive-interval=30"
|
||||
#endif
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
",mptcp=off"
|
||||
#endif
|
||||
, &exp_addr, true);
|
||||
}
|
||||
|
||||
static void test_inet_parse_all_implicit_bool_good(void)
|
||||
{
|
||||
char host[] = "::1";
|
||||
char port[] = "5000";
|
||||
InetSocketAddress exp_addr = {
|
||||
.host = host,
|
||||
.port = port,
|
||||
.has_numeric = true,
|
||||
.numeric = true,
|
||||
.has_to = true,
|
||||
.to = 5006,
|
||||
.has_ipv4 = true,
|
||||
.ipv4 = true,
|
||||
.has_ipv6 = true,
|
||||
.ipv6 = true,
|
||||
.has_keep_alive = true,
|
||||
.keep_alive = true,
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
.has_mptcp = true,
|
||||
.mptcp = true,
|
||||
#endif
|
||||
};
|
||||
inet_parse_test_helper(
|
||||
"[::1]:5000,numeric,to=5006,ipv4,ipv6,keep-alive"
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
",mptcp"
|
||||
#endif
|
||||
, &exp_addr, true);
|
||||
}
|
||||
|
||||
int main(int argc, char **argv)
|
||||
{
|
||||
bool has_ipv4, has_ipv6;
|
||||
|
|
@ -377,6 +587,31 @@ int main(int argc, char **argv)
|
|||
test_socket_unix_abstract);
|
||||
#endif
|
||||
|
||||
g_test_add_func("/util/socket/inet-parse/nohost-good",
|
||||
test_inet_parse_nohost_good);
|
||||
g_test_add_func("/util/socket/inet-parse/empty-bad",
|
||||
test_inet_parse_empty_bad);
|
||||
g_test_add_func("/util/socket/inet-parse/only-colon-bad",
|
||||
test_inet_parse_only_colon_bad);
|
||||
g_test_add_func("/util/socket/inet-parse/ipv4-good",
|
||||
test_inet_parse_ipv4_good);
|
||||
g_test_add_func("/util/socket/inet-parse/ipv4-noport-bad",
|
||||
test_inet_parse_ipv4_noport_bad);
|
||||
g_test_add_func("/util/socket/inet-parse/ipv6-good",
|
||||
test_inet_parse_ipv6_good);
|
||||
g_test_add_func("/util/socket/inet-parse/ipv6-noend-bad",
|
||||
test_inet_parse_ipv6_noend_bad);
|
||||
g_test_add_func("/util/socket/inet-parse/ipv6-noport-bad",
|
||||
test_inet_parse_ipv6_noport_bad);
|
||||
g_test_add_func("/util/socket/inet-parse/ipv6-empty-bad",
|
||||
test_inet_parse_ipv6_empty_bad);
|
||||
g_test_add_func("/util/socket/inet-parse/hostname-good",
|
||||
test_inet_parse_hostname_good);
|
||||
g_test_add_func("/util/socket/inet-parse/all-options-good",
|
||||
test_inet_parse_all_options_good);
|
||||
g_test_add_func("/util/socket/inet-parse/all-bare-bool-good",
|
||||
test_inet_parse_all_implicit_bool_good);
|
||||
|
||||
end:
|
||||
return g_test_run();
|
||||
}
|
||||
|
|
|
|||
|
|
@ -126,33 +126,34 @@ uint32_t qemu_pixman_to_drm_format(pixman_format_code_t pixman_format)
|
|||
return 0;
|
||||
}
|
||||
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift)
|
||||
int qemu_pixman_get_type(int rshift, int gshift, int bshift, int endian)
|
||||
{
|
||||
int type = PIXMAN_TYPE_OTHER;
|
||||
bool native_endian = (endian == G_BYTE_ORDER);
|
||||
|
||||
if (rshift > gshift && gshift > bshift) {
|
||||
if (bshift == 0) {
|
||||
type = PIXMAN_TYPE_ARGB;
|
||||
type = native_endian ? PIXMAN_TYPE_ARGB : PIXMAN_TYPE_BGRA;
|
||||
} else {
|
||||
type = PIXMAN_TYPE_RGBA;
|
||||
type = native_endian ? PIXMAN_TYPE_RGBA : PIXMAN_TYPE_ABGR;
|
||||
}
|
||||
} else if (rshift < gshift && gshift < bshift) {
|
||||
if (rshift == 0) {
|
||||
type = PIXMAN_TYPE_ABGR;
|
||||
type = native_endian ? PIXMAN_TYPE_ABGR : PIXMAN_TYPE_RGBA;
|
||||
} else {
|
||||
type = PIXMAN_TYPE_BGRA;
|
||||
type = native_endian ? PIXMAN_TYPE_BGRA : PIXMAN_TYPE_ARGB;
|
||||
}
|
||||
}
|
||||
return type;
|
||||
}
|
||||
|
||||
#ifdef CONFIG_PIXMAN
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf)
|
||||
pixman_format_code_t qemu_pixman_get_format(PixelFormat *pf, int endian)
|
||||
{
|
||||
pixman_format_code_t format;
|
||||
int type;
|
||||
|
||||
type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift);
|
||||
type = qemu_pixman_get_type(pf->rshift, pf->gshift, pf->bshift, endian);
|
||||
format = PIXMAN_FORMAT(pf->bits_per_pixel, type,
|
||||
pf->abits, pf->rbits, pf->gbits, pf->bbits);
|
||||
if (!pixman_format_supported_source(format)) {
|
||||
|
|
|
|||
|
|
@ -150,7 +150,7 @@ tight_detect_smooth_image24(VncState *vs, int w, int h)
|
|||
* If client is big-endian, color samples begin from the second
|
||||
* byte (offset 1) of a 32-bit pixel value.
|
||||
*/
|
||||
off = vs->client_be;
|
||||
off = vs->client_endian == G_BIG_ENDIAN ? 1 : 0;
|
||||
|
||||
memset(stats, 0, sizeof (stats));
|
||||
|
||||
|
|
@ -891,7 +891,7 @@ static void tight_pack24(VncState *vs, uint8_t *buf, size_t count, size_t *ret)
|
|||
|
||||
buf8 = buf;
|
||||
|
||||
if (1 /* FIXME */) {
|
||||
if (vs->client_endian == G_BYTE_ORDER) {
|
||||
rshift = vs->client_pf.rshift;
|
||||
gshift = vs->client_pf.gshift;
|
||||
bshift = vs->client_pf.bshift;
|
||||
|
|
@ -1001,16 +1001,24 @@ static int send_mono_rect(VncState *vs, int x, int y,
|
|||
break;
|
||||
}
|
||||
case 2:
|
||||
vnc_write(vs, &bg, 2);
|
||||
vnc_write(vs, &fg, 2);
|
||||
{
|
||||
uint16_t bg16 = bg;
|
||||
uint16_t fg16 = fg;
|
||||
vnc_write(vs, &bg16, 2);
|
||||
vnc_write(vs, &fg16, 2);
|
||||
tight_encode_mono_rect16(vs->tight->tight.buffer, w, h, bg, fg);
|
||||
break;
|
||||
}
|
||||
default:
|
||||
vnc_write_u8(vs, bg);
|
||||
vnc_write_u8(vs, fg);
|
||||
{
|
||||
uint8_t bg8 = bg;
|
||||
uint8_t fg8 = fg;
|
||||
vnc_write_u8(vs, bg8);
|
||||
vnc_write_u8(vs, fg8);
|
||||
tight_encode_mono_rect8(vs->tight->tight.buffer, w, h, bg, fg);
|
||||
break;
|
||||
}
|
||||
}
|
||||
vs->tight->tight.offset = bytes;
|
||||
|
||||
bytes = tight_compress_data(vs, stream, bytes, level, Z_DEFAULT_STRATEGY);
|
||||
|
|
|
|||
|
|
@ -255,7 +255,7 @@ static void zrle_write_u8(VncState *vs, uint8_t value)
|
|||
static int zrle_send_framebuffer_update(VncState *vs, int x, int y,
|
||||
int w, int h)
|
||||
{
|
||||
bool be = vs->client_be;
|
||||
bool be = vs->client_endian == G_BIG_ENDIAN;
|
||||
size_t bytes;
|
||||
int zywrle_level;
|
||||
|
||||
|
|
|
|||
|
|
@ -188,7 +188,7 @@ static void vnc_async_encoding_start(VncState *orig, VncState *local)
|
|||
local->lossy_rect = orig->lossy_rect;
|
||||
local->write_pixels = orig->write_pixels;
|
||||
local->client_pf = orig->client_pf;
|
||||
local->client_be = orig->client_be;
|
||||
local->client_endian = orig->client_endian;
|
||||
local->tight = orig->tight;
|
||||
local->zlib = orig->zlib;
|
||||
local->hextile = orig->hextile;
|
||||
|
|
|
|||
9
ui/vnc.c
9
ui/vnc.c
|
|
@ -891,7 +891,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
|
|||
buf[0] = v;
|
||||
break;
|
||||
case 2:
|
||||
if (vs->client_be) {
|
||||
if (vs->client_endian == G_BIG_ENDIAN) {
|
||||
buf[0] = v >> 8;
|
||||
buf[1] = v;
|
||||
} else {
|
||||
|
|
@ -901,7 +901,7 @@ void vnc_convert_pixel(VncState *vs, uint8_t *buf, uint32_t v)
|
|||
break;
|
||||
default:
|
||||
case 4:
|
||||
if (vs->client_be) {
|
||||
if (vs->client_endian == G_BIG_ENDIAN) {
|
||||
buf[0] = v >> 24;
|
||||
buf[1] = v >> 16;
|
||||
buf[2] = v >> 8;
|
||||
|
|
@ -2240,7 +2240,8 @@ static void set_encodings(VncState *vs, int32_t *encodings, size_t n_encodings)
|
|||
|
||||
static void set_pixel_conversion(VncState *vs)
|
||||
{
|
||||
pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf);
|
||||
pixman_format_code_t fmt = qemu_pixman_get_format(&vs->client_pf,
|
||||
vs->client_endian);
|
||||
|
||||
if (fmt == VNC_SERVER_FB_FORMAT) {
|
||||
vs->write_pixels = vnc_write_pixels_copy;
|
||||
|
|
@ -2312,7 +2313,7 @@ static void set_pixel_format(VncState *vs, int bits_per_pixel,
|
|||
vs->client_pf.bits_per_pixel = bits_per_pixel;
|
||||
vs->client_pf.bytes_per_pixel = bits_per_pixel / 8;
|
||||
vs->client_pf.depth = bits_per_pixel == 32 ? 24 : bits_per_pixel;
|
||||
vs->client_be = big_endian_flag;
|
||||
vs->client_endian = big_endian_flag ? G_BIG_ENDIAN : G_LITTLE_ENDIAN;
|
||||
|
||||
if (!true_color_flag) {
|
||||
send_color_map(vs);
|
||||
|
|
|
|||
2
ui/vnc.h
2
ui/vnc.h
|
|
@ -323,7 +323,7 @@ struct VncState
|
|||
VncWritePixels *write_pixels;
|
||||
PixelFormat client_pf;
|
||||
pixman_format_code_t client_format;
|
||||
bool client_be;
|
||||
int client_endian; /* G_LITTLE_ENDIAN or G_BIG_ENDIAN */
|
||||
|
||||
CaptureVoiceOut *audio_cap;
|
||||
struct audsettings as;
|
||||
|
|
|
|||
|
|
@ -30,6 +30,7 @@
|
|||
#include "qapi/qobject-input-visitor.h"
|
||||
#include "qapi/qobject-output-visitor.h"
|
||||
#include "qemu/cutils.h"
|
||||
#include "qemu/option.h"
|
||||
#include "trace.h"
|
||||
|
||||
#ifndef AI_ADDRCONFIG
|
||||
|
|
@ -44,6 +45,14 @@
|
|||
# define AI_NUMERICSERV 0
|
||||
#endif
|
||||
|
||||
/*
|
||||
* On macOS TCP_KEEPIDLE is available under a different name, TCP_KEEPALIVE.
|
||||
* https://github.com/apple/darwin-xnu/blob/xnu-4570.1.46/bsd/man/man4/tcp.4#L172
|
||||
*/
|
||||
#if defined(TCP_KEEPALIVE) && !defined(TCP_KEEPIDLE)
|
||||
# define TCP_KEEPIDLE TCP_KEEPALIVE
|
||||
#endif
|
||||
|
||||
|
||||
static int inet_getport(struct addrinfo *e)
|
||||
{
|
||||
|
|
@ -205,6 +214,58 @@ static int try_bind(int socket, InetSocketAddress *saddr, struct addrinfo *e)
|
|||
#endif
|
||||
}
|
||||
|
||||
static int inet_set_sockopts(int sock, InetSocketAddress *saddr, Error **errp)
|
||||
{
|
||||
if (saddr->keep_alive) {
|
||||
int keep_alive = 1;
|
||||
int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
|
||||
&keep_alive, sizeof(keep_alive));
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"Unable to set keep-alive option on socket");
|
||||
return -1;
|
||||
}
|
||||
#ifdef HAVE_TCP_KEEPCNT
|
||||
if (saddr->has_keep_alive_count && saddr->keep_alive_count) {
|
||||
int keep_count = saddr->keep_alive_count;
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPCNT, &keep_count,
|
||||
sizeof(keep_count));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"Unable to set TCP keep-alive count option on socket");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPIDLE
|
||||
if (saddr->has_keep_alive_idle && saddr->keep_alive_idle) {
|
||||
int keep_idle = saddr->keep_alive_idle;
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPIDLE, &keep_idle,
|
||||
sizeof(keep_idle));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"Unable to set TCP keep-alive idle option on socket");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPINTVL
|
||||
if (saddr->has_keep_alive_interval && saddr->keep_alive_interval) {
|
||||
int keep_interval = saddr->keep_alive_interval;
|
||||
ret = setsockopt(sock, IPPROTO_TCP, TCP_KEEPINTVL, &keep_interval,
|
||||
sizeof(keep_interval));
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, errno,
|
||||
"Unable to set TCP keep-alive interval option on socket");
|
||||
return -1;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
|
||||
static int inet_listen_saddr(InetSocketAddress *saddr,
|
||||
int port_offset,
|
||||
int num,
|
||||
|
|
@ -220,12 +281,6 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
|
|||
int saved_errno = 0;
|
||||
bool socket_created = false;
|
||||
|
||||
if (saddr->keep_alive) {
|
||||
error_setg(errp, "keep-alive option is not supported for passive "
|
||||
"sockets");
|
||||
return -1;
|
||||
}
|
||||
|
||||
memset(&ai,0, sizeof(ai));
|
||||
ai.ai_flags = AI_PASSIVE;
|
||||
if (saddr->has_numeric && saddr->numeric) {
|
||||
|
|
@ -287,11 +342,20 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
|
|||
port_min = inet_getport(e);
|
||||
port_max = saddr->has_to ? saddr->to + port_offset : port_min;
|
||||
for (p = port_min; p <= port_max; p++) {
|
||||
if (slisten >= 0) {
|
||||
/*
|
||||
* We have a socket we tried with the previous port. It cannot
|
||||
* be rebound, we need to close it and create a new one.
|
||||
*/
|
||||
close(slisten);
|
||||
slisten = -1;
|
||||
}
|
||||
inet_setport(e, p);
|
||||
|
||||
slisten = create_fast_reuse_socket(e);
|
||||
if (slisten < 0) {
|
||||
/* First time we expect we might fail to create the socket
|
||||
/*
|
||||
* First time we expect we might fail to create the socket
|
||||
* eg if 'e' has AF_INET6 but ipv6 kmod is not loaded.
|
||||
* Later iterations should always succeed if first iteration
|
||||
* worked though, so treat that as fatal.
|
||||
|
|
@ -301,40 +365,41 @@ static int inet_listen_saddr(InetSocketAddress *saddr,
|
|||
} else {
|
||||
error_setg_errno(errp, errno,
|
||||
"Failed to recreate failed listening socket");
|
||||
goto listen_failed;
|
||||
goto fail;
|
||||
}
|
||||
}
|
||||
socket_created = true;
|
||||
|
||||
rc = try_bind(slisten, saddr, e);
|
||||
if (rc < 0) {
|
||||
if (errno != EADDRINUSE) {
|
||||
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||
goto listen_failed;
|
||||
}
|
||||
} else {
|
||||
if (!listen(slisten, num)) {
|
||||
goto listen_ok;
|
||||
}
|
||||
if (errno != EADDRINUSE) {
|
||||
error_setg_errno(errp, errno, "Failed to listen on socket");
|
||||
goto listen_failed;
|
||||
if (errno == EADDRINUSE) {
|
||||
/* This port is already used, try the next one */
|
||||
continue;
|
||||
}
|
||||
error_setg_errno(errp, errno, "Failed to bind socket");
|
||||
goto fail;
|
||||
}
|
||||
/* Someone else managed to bind to the same port and beat us
|
||||
* to listen on it! Socket semantics does not allow us to
|
||||
* recover from this situation, so we need to recreate the
|
||||
* socket to allow bind attempts for subsequent ports:
|
||||
*/
|
||||
close(slisten);
|
||||
slisten = -1;
|
||||
if (listen(slisten, num)) {
|
||||
if (errno == EADDRINUSE) {
|
||||
/* This port is already used, try the next one */
|
||||
continue;
|
||||
}
|
||||
error_setg_errno(errp, errno, "Failed to listen on socket");
|
||||
goto fail;
|
||||
}
|
||||
/* We have a listening socket */
|
||||
if (inet_set_sockopts(slisten, saddr, errp) < 0) {
|
||||
goto fail;
|
||||
}
|
||||
freeaddrinfo(res);
|
||||
return slisten;
|
||||
}
|
||||
}
|
||||
error_setg_errno(errp, errno,
|
||||
socket_created ?
|
||||
"Failed to find an available port" :
|
||||
"Failed to create a socket");
|
||||
listen_failed:
|
||||
fail:
|
||||
saved_errno = errno;
|
||||
if (slisten >= 0) {
|
||||
close(slisten);
|
||||
|
|
@ -342,10 +407,6 @@ listen_failed:
|
|||
freeaddrinfo(res);
|
||||
errno = saved_errno;
|
||||
return -1;
|
||||
|
||||
listen_ok:
|
||||
freeaddrinfo(res);
|
||||
return slisten;
|
||||
}
|
||||
|
||||
#ifdef _WIN32
|
||||
|
|
@ -475,16 +536,9 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp)
|
|||
return sock;
|
||||
}
|
||||
|
||||
if (saddr->keep_alive) {
|
||||
int val = 1;
|
||||
int ret = setsockopt(sock, SOL_SOCKET, SO_KEEPALIVE,
|
||||
&val, sizeof(val));
|
||||
|
||||
if (ret < 0) {
|
||||
error_setg_errno(errp, errno, "Unable to set KEEPALIVE");
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
if (inet_set_sockopts(sock, saddr, errp) < 0) {
|
||||
close(sock);
|
||||
return -1;
|
||||
}
|
||||
|
||||
return sock;
|
||||
|
|
@ -591,115 +645,140 @@ err:
|
|||
return -1;
|
||||
}
|
||||
|
||||
/* compatibility wrapper */
|
||||
static int inet_parse_flag(const char *flagname, const char *optstr, bool *val,
|
||||
Error **errp)
|
||||
{
|
||||
char *end;
|
||||
size_t len;
|
||||
|
||||
end = strstr(optstr, ",");
|
||||
if (end) {
|
||||
if (end[1] == ',') { /* Reject 'ipv6=on,,foo' */
|
||||
error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr);
|
||||
return -1;
|
||||
}
|
||||
len = end - optstr;
|
||||
} else {
|
||||
len = strlen(optstr);
|
||||
}
|
||||
if (len == 0 || (len == 3 && strncmp(optstr, "=on", len) == 0)) {
|
||||
*val = true;
|
||||
} else if (len == 4 && strncmp(optstr, "=off", len) == 0) {
|
||||
*val = false;
|
||||
} else {
|
||||
error_setg(errp, "error parsing '%s' flag '%s'", flagname, optstr);
|
||||
return -1;
|
||||
}
|
||||
return 0;
|
||||
}
|
||||
static QemuOptsList inet_opts = {
|
||||
.name = "InetSocketAddress",
|
||||
.head = QTAILQ_HEAD_INITIALIZER(inet_opts.head),
|
||||
.implied_opt_name = "addr",
|
||||
.desc = {
|
||||
{
|
||||
.name = "addr",
|
||||
.type = QEMU_OPT_STRING,
|
||||
},
|
||||
{
|
||||
.name = "numeric",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{
|
||||
.name = "to",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
{
|
||||
.name = "ipv4",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{
|
||||
.name = "ipv6",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
{
|
||||
.name = "keep-alive",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
#ifdef HAVE_TCP_KEEPCNT
|
||||
{
|
||||
.name = "keep-alive-count",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPIDLE
|
||||
{
|
||||
.name = "keep-alive-idle",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPINTVL
|
||||
{
|
||||
.name = "keep-alive-interval",
|
||||
.type = QEMU_OPT_NUMBER,
|
||||
},
|
||||
#endif
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
{
|
||||
.name = "mptcp",
|
||||
.type = QEMU_OPT_BOOL,
|
||||
},
|
||||
#endif
|
||||
{ /* end of list */ }
|
||||
},
|
||||
};
|
||||
|
||||
int inet_parse(InetSocketAddress *addr, const char *str, Error **errp)
|
||||
{
|
||||
const char *optstr, *h;
|
||||
char host[65];
|
||||
char port[33];
|
||||
int to;
|
||||
int pos;
|
||||
char *begin;
|
||||
|
||||
QemuOpts *opts = qemu_opts_parse(&inet_opts, str, true, errp);
|
||||
if (!opts) {
|
||||
return -1;
|
||||
}
|
||||
memset(addr, 0, sizeof(*addr));
|
||||
|
||||
/* parse address */
|
||||
if (str[0] == ':') {
|
||||
/* no host given */
|
||||
host[0] = '\0';
|
||||
if (sscanf(str, ":%32[^,]%n", port, &pos) != 1) {
|
||||
error_setg(errp, "error parsing port in address '%s'", str);
|
||||
return -1;
|
||||
}
|
||||
} else if (str[0] == '[') {
|
||||
/* IPv6 addr */
|
||||
if (sscanf(str, "[%64[^]]]:%32[^,]%n", host, port, &pos) != 2) {
|
||||
error_setg(errp, "error parsing IPv6 address '%s'", str);
|
||||
return -1;
|
||||
}
|
||||
} else {
|
||||
/* hostname or IPv4 addr */
|
||||
if (sscanf(str, "%64[^:]:%32[^,]%n", host, port, &pos) != 2) {
|
||||
error_setg(errp, "error parsing address '%s'", str);
|
||||
return -1;
|
||||
}
|
||||
const char *addr_str = qemu_opt_get(opts, "addr");
|
||||
if (!addr_str) {
|
||||
error_setg(errp, "error parsing address ''");
|
||||
return -1;
|
||||
}
|
||||
if (str[0] == '[') {
|
||||
/* IPv6 addr */
|
||||
const char *ip_end = strstr(addr_str, "]:");
|
||||
if (!ip_end || ip_end - addr_str < 2 || strlen(ip_end) < 3) {
|
||||
error_setg(errp, "error parsing IPv6 address '%s'", addr_str);
|
||||
return -1;
|
||||
}
|
||||
addr->host = g_strndup(addr_str + 1, ip_end - addr_str - 1);
|
||||
addr->port = g_strdup(ip_end + 2);
|
||||
} else {
|
||||
/* no host, hostname or IPv4 addr */
|
||||
const char *port = strchr(addr_str, ':');
|
||||
if (!port || strlen(port) < 2) {
|
||||
error_setg(errp, "error parsing address '%s'", addr_str);
|
||||
return -1;
|
||||
}
|
||||
addr->host = g_strndup(addr_str, port - addr_str);
|
||||
addr->port = g_strdup(port + 1);
|
||||
}
|
||||
|
||||
addr->host = g_strdup(host);
|
||||
addr->port = g_strdup(port);
|
||||
|
||||
/* parse options */
|
||||
optstr = str + pos;
|
||||
h = strstr(optstr, ",to=");
|
||||
if (h) {
|
||||
h += 4;
|
||||
if (sscanf(h, "%d%n", &to, &pos) != 1 ||
|
||||
(h[pos] != '\0' && h[pos] != ',')) {
|
||||
error_setg(errp, "error parsing to= argument");
|
||||
return -1;
|
||||
}
|
||||
if (qemu_opt_find(opts, "numeric")) {
|
||||
addr->has_numeric = true,
|
||||
addr->numeric = qemu_opt_get_bool(opts, "numeric", false);
|
||||
}
|
||||
if (qemu_opt_find(opts, "to")) {
|
||||
addr->has_to = true;
|
||||
addr->to = to;
|
||||
addr->to = qemu_opt_get_number(opts, "to", 0);
|
||||
}
|
||||
begin = strstr(optstr, ",ipv4");
|
||||
if (begin) {
|
||||
if (inet_parse_flag("ipv4", begin + 5, &addr->ipv4, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (qemu_opt_find(opts, "ipv4")) {
|
||||
addr->has_ipv4 = true;
|
||||
addr->ipv4 = qemu_opt_get_bool(opts, "ipv4", false);
|
||||
}
|
||||
begin = strstr(optstr, ",ipv6");
|
||||
if (begin) {
|
||||
if (inet_parse_flag("ipv6", begin + 5, &addr->ipv6, errp) < 0) {
|
||||
return -1;
|
||||
}
|
||||
if (qemu_opt_find(opts, "ipv6")) {
|
||||
addr->has_ipv6 = true;
|
||||
addr->ipv6 = qemu_opt_get_bool(opts, "ipv6", false);
|
||||
}
|
||||
begin = strstr(optstr, ",keep-alive");
|
||||
if (begin) {
|
||||
if (inet_parse_flag("keep-alive", begin + strlen(",keep-alive"),
|
||||
&addr->keep_alive, errp) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (qemu_opt_find(opts, "keep-alive")) {
|
||||
addr->has_keep_alive = true;
|
||||
addr->keep_alive = qemu_opt_get_bool(opts, "keep-alive", false);
|
||||
}
|
||||
#ifdef HAVE_TCP_KEEPCNT
|
||||
if (qemu_opt_find(opts, "keep-alive-count")) {
|
||||
addr->has_keep_alive_count = true;
|
||||
addr->keep_alive_count = qemu_opt_get_number(opts, "keep-alive-count", 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPIDLE
|
||||
if (qemu_opt_find(opts, "keep-alive-idle")) {
|
||||
addr->has_keep_alive_idle = true;
|
||||
addr->keep_alive_idle = qemu_opt_get_number(opts, "keep-alive-idle", 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_TCP_KEEPINTVL
|
||||
if (qemu_opt_find(opts, "keep-alive-interval")) {
|
||||
addr->has_keep_alive_interval = true;
|
||||
addr->keep_alive_interval = qemu_opt_get_number(opts, "keep-alive-interval", 0);
|
||||
}
|
||||
#endif
|
||||
#ifdef HAVE_IPPROTO_MPTCP
|
||||
begin = strstr(optstr, ",mptcp");
|
||||
if (begin) {
|
||||
if (inet_parse_flag("mptcp", begin + strlen(",mptcp"),
|
||||
&addr->mptcp, errp) < 0)
|
||||
{
|
||||
return -1;
|
||||
}
|
||||
if (qemu_opt_find(opts, "mptcp")) {
|
||||
addr->has_mptcp = true;
|
||||
addr->mptcp = qemu_opt_get_bool(opts, "mptcp", 0);
|
||||
}
|
||||
#endif
|
||||
return 0;
|
||||
|
|
|
|||
Loading…
Add table
Add a link
Reference in a new issue