From nobody Wed Sep 23 07:34:02 2026 Delivered-To: importer@patchew.org Received-SPF: pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) client-ip=38.145.34.151; envelope-from=devel-bounces@lists.libvirt.org; helo=lists.libvirt.org; Authentication-Results: mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass(p=reject dis=none) header.from=lists.libvirt.org ARC-Seal: i=1; a=rsa-sha256; t=1783604973; cv=none; d=zohomail.com; s=zohoarc; b=VAu5bQ0w9F7ypOkU208Y2wutFhO+ZI1E2ONDHT/4cjGXzTyPg+gDHrNyXPWEb81Weh0/Xhpod27q+YROUz2s8e4GGvhPNqfoO9FyDn/RJZDgN8f3CzXyVLim/3YLOGV87Z5tzHst8Z+OTY4BPkDEKt1tqDy6O7fr3ZXg2Ysxj5Q= ARC-Message-Signature: i=1; a=rsa-sha256; c=relaxed/relaxed; d=zohomail.com; s=zohoarc; t=1783604973; h=Content-Transfer-Encoding:Date:Date:From:From:In-Reply-To:List-Subscribe:List-Post:List-Owner:List-Id:List-Archive:List-Help:List-Unsubscribe:MIME-Version:Message-ID:Reply-To:Reply-To:References:Subject:Subject:To:To:Message-Id:Cc; bh=B4+oPiiSLA8lSn//DmeMuFt13iUudlT/lx4X5aVo5/A=; b=GbdtfIphJmLLiuahhdkgTLSKASTohBlC2xWp9v6WhYyOF/sp0iNqvirTldlmla2DqigIuNT0u6KnIob8q1lOnwftJOGYEo904ySq7/gRAoF6+EdA/mYWp2IswG7QdBV3/AsI6Xa+YBoO4EhsWswHWQxcGG/nu1zVQQ9liOeq/1E= ARC-Authentication-Results: i=1; mx.zohomail.com; dkim=fail; spf=pass (zohomail.com: domain of lists.libvirt.org designates 38.145.34.151 as permitted sender) smtp.mailfrom=devel-bounces@lists.libvirt.org; dmarc=pass header.from= (p=reject dis=none) Return-Path: Received: from lists.libvirt.org (lists.libvirt.org [38.145.34.151]) by mx.zohomail.com with SMTPS id 1783604973267275.48971423817795; Thu, 9 Jul 2026 06:49:33 -0700 (PDT) Received: by lists.libvirt.org (Postfix, from userid 993) id C7D3441D09; Thu, 9 Jul 2026 09:49:31 -0400 (EDT) Received: from [172.19.199.10] (unknown [10.16.107.18]) by lists.libvirt.org (Postfix) with ESMTP id C609241CD0; Thu, 9 Jul 2026 09:41:25 -0400 (EDT) Received: by lists.libvirt.org (Postfix, from userid 993) id CC7A941AC1; Thu, 9 Jul 2026 09:38:32 -0400 (EDT) Received: from relay.virtuozzo.com (relay.virtuozzo.com [130.117.225.111]) (using TLSv1.3 with cipher TLS_AES_256_GCM_SHA384 (256/256 bits) key-exchange X25519 server-signature RSA-PSS (3072 bits) server-digest SHA256) (No client certificate requested) by lists.libvirt.org (Postfix) with ESMTPS id 1ADCF41AC1 for ; Thu, 9 Jul 2026 09:38:30 -0400 (EDT) Received: from ch-vpn.virtuozzo.com ([130.117.225.6] helo=mami) by relay.virtuozzo.com with esmtp (Exim 4.96) (envelope-from ) id 1whoh4-006MF9-2n for devel@lists.libvirt.org; Thu, 09 Jul 2026 15:22:38 +0200 X-Spam-Checker-Version: SpamAssassin 4.0.1 (2024-03-26) on lists.libvirt.org X-Spam-Level: X-Spam-Status: No, score=-5.0 required=5.0 tests=BAYES_00,DKIM_INVALID, DKIM_SIGNED,MAILING_LIST_MULTI,RCVD_IN_DNSWL_MED,SPF_HELO_NONE autolearn=unavailable autolearn_force=no version=4.0.1 DKIM-Signature: v=1; a=rsa-sha256; q=dns/txt; c=relaxed/relaxed; d=virtuozzo.com; s=relay; h=MIME-Version:Message-ID:Date:Subject:From: Content-Type; bh=B4+oPiiSLA8lSn//DmeMuFt13iUudlT/lx4X5aVo5/A=; b=wkOSy0PyluhK JbkpfxpyRMDqLfvluE2DkVWyFIA8mcyzgDrEcdJ1fn5+SAe1aHTYIBdwyjUKg3TJ8FYoG0sSzESp4 zmcOrZgMhMYfbslX1rreevXmSxdN76ZJKYsJKrMYHZyMGG7p4F+7ft6cUPIbS4KTrQ9Q5BHHhpl5u 3c/FX51eiCcccrXKHc0JPKsRdNdCLPtheraXWrJa2QcBrXq6xXhcuEeOQOLoiEAVsOrRGlU+cRedR 3IzLjlU74oaGkwedJmMrLkriEDmj6+hNvZmNX/pdP5wh2pYoYSoG3oQqOcNEERi8ES+eUc1c9KkqV QwsGtfOEVv2WRwQCOxH0+g==; To: devel@lists.libvirt.org Subject: [PATCH 5/6] tests: Add a unit test for virVsockConnectQuiet() Date: Thu, 9 Jul 2026 15:15:18 +0200 Message-ID: <20260709132213.2392145-6-polina.vishneva@virtuozzo.com> X-Mailer: git-send-email 2.54.0 In-Reply-To: <20260709132213.2392145-1-polina.vishneva@virtuozzo.com> References: <20260709132213.2392145-1-polina.vishneva@virtuozzo.com> MIME-Version: 1.0 Content-Transfer-Encoding: quoted-printable X-MailFrom: polina.vishneva@virtuozzo.com X-Mailman-Rule-Hits: nonmember-moderation X-Mailman-Rule-Misses: dmarc-mitigation; no-senders; approved; loop; banned-address; header-match-devel.lists.libvirt.org-0; emergency; member-moderation Message-ID-Hash: FID56EHSVVUILJRGUA7U5YCFSXWDAS6X X-Message-ID-Hash: FID56EHSVVUILJRGUA7U5YCFSXWDAS6X X-Mailman-Approved-At: Thu, 09 Jul 2026 13:40:43 +0000 X-Mailman-Version: 3.3.10 Precedence: list List-Id: Development discussions about the libvirt library & tools Archived-At: List-Archive: List-Help: List-Owner: List-Post: List-Subscribe: List-Unsubscribe: From: Polina Vishneva via Devel Reply-To: Polina Vishneva X-ZohoMail-DKIM: fail (Header signature does not verify) X-ZM-MESSAGEID: 1783604974383158500 Content-Type: text/plain; charset="utf-8" Mock the three syscalls so its address construction, connect-timeout option and errno preservation are checked without a real AF_VSOCK socket. Signed-off-by: Polina Vishneva --- tests/meson.build | 2 + tests/virvsockmock.c | 143 +++++++++++++++++++++++++++++++++++++++++++ tests/virvsocktest.c | 133 ++++++++++++++++++++++++++++++++++++++++ 3 files changed, 278 insertions(+) create mode 100644 tests/virvsockmock.c create mode 100644 tests/virvsocktest.c diff --git a/tests/meson.build b/tests/meson.build index ea50f89fb5..63e0474a29 100644 --- a/tests/meson.build +++ b/tests/meson.build @@ -94,6 +94,7 @@ if host_machine.system() =3D=3D 'linux' { 'name': 'virnetdevbandwidthmock' }, { 'name': 'virtestmock' }, { 'name': 'virusbmock' }, + { 'name': 'virvsockmock' }, ] endif =20 @@ -337,6 +338,7 @@ if host_machine.system() =3D=3D 'linux' { 'name': 'virresctrltest', 'link_whole': [ test_file_wrapper_lib ] }, { 'name': 'virscsitest' }, { 'name': 'virusbtest' }, + { 'name': 'virvsocktest' }, ] if conf.has('WITH_JSON') tests +=3D [ diff --git a/tests/virvsockmock.c b/tests/virvsockmock.c new file mode 100644 index 0000000000..a951ad5845 --- /dev/null +++ b/tests/virvsockmock.c @@ -0,0 +1,143 @@ +/* + * Copyright (C) 2026 Virtuozzo International GmbH + * + * 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 + * . + */ + +#include + +#include "virmock.h" +#include "virstring.h" + +#include +#include +#include + +#ifdef __linux__ +# include +# include +# ifndef SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD +# define SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD SO_VM_SOCKETS_CONNECT_TIMEOUT +# endif +#endif + +#if defined(__linux__) && defined(RTLD_NEXT) + +static int (*real_socket)(int domain, int type, int protocol); +static int (*real_setsockopt)(int sockfd, int level, int optname, + const void *optval, socklen_t optlen); +static int (*real_connect)(int sockfd, const struct sockaddr *addr, + socklen_t addrlen); + +/* Microseconds passed to the connect-timeout setsockopt() during the curr= ent + * attempt, or -1 if it wasn't set. Reset by socket() and checked by conne= ct() + * so a dropped timeout can't pass on a stale value from an earlier attemp= t. */ +static long long appliedTimeoutUs =3D -1; + +static void +init_syms(void) +{ + if (real_socket) + return; + + VIR_MOCK_REAL_INIT(socket); + VIR_MOCK_REAL_INIT(setsockopt); + VIR_MOCK_REAL_INIT(connect); +} + +/* Read a base-10 long long from environment variable @name into @out, + * returning false (leaving @out untouched) when it is unset or unparseabl= e. */ +static bool +get_expected_ll(const char *name, long long *out) +{ + const char *s =3D getenv(name); + + return s && virStrToLong_ll(s, NULL, 10, out) =3D=3D 0; +} + +int +socket(int domain, int type, int protocol) +{ + init_syms(); + + /* Hand back a real, closable fd, and start a fresh attempt by forgett= ing + * any previously applied timeout. */ + if (domain =3D=3D AF_VSOCK) { + appliedTimeoutUs =3D -1; + return real_socket(AF_UNIX, type, protocol); + } + + return real_socket(domain, type, protocol); +} + +int +setsockopt(int sockfd, int level, int optname, + const void *optval, socklen_t optlen) +{ + init_syms(); + + /* vsock options use AF_VSOCK as the level. Decode only the connect + * timeout; swallow any other vsock option so it can't reach the AF_UN= IX + * fd we handed back from socket(). */ + if (level =3D=3D AF_VSOCK) { + if (optname =3D=3D SO_VM_SOCKETS_CONNECT_TIMEOUT_OLD && optval) { + const struct __kernel_old_timeval *tv =3D optval; + + appliedTimeoutUs =3D tv->tv_sec * 1000000LL + tv->tv_usec; + } + return 0; + } + + return real_setsockopt(sockfd, level, optname, optval, optlen); +} + +int +connect(int sockfd, const struct sockaddr *addr, socklen_t addrlen) +{ + init_syms(); + + if (addr && addr->sa_family =3D=3D AF_VSOCK) { + const struct sockaddr_vm *svm =3D (const struct sockaddr_vm *)(con= st void *)addr; + const char *errstr =3D getenv("LIBVIRT_VSOCK_MOCK_CONNECT_ERRNO"); + long long expected; + int err =3D 0; + + /* The test declares, via the environment, what production must ha= ve put + * on the wire; a mismatch fails the connect just like a bad reque= st + * would, so the test only needs to check the return value. */ + if ((get_expected_ll("LIBVIRT_VSOCK_MOCK_EXPECT_CID", &expected) && + svm->svm_cid !=3D expected) || + (get_expected_ll("LIBVIRT_VSOCK_MOCK_EXPECT_PORT", &expected) = && + svm->svm_port !=3D expected) || + (get_expected_ll("LIBVIRT_VSOCK_MOCK_EXPECT_TIMEOUT_US", &expe= cted) && + appliedTimeoutUs !=3D expected)) { + errno =3D EINVAL; + return -1; + } + + if (errstr) + ignore_value(virStrToLong_i(errstr, NULL, 10, &err)); + + if (err !=3D 0) { + errno =3D err; + return -1; + } + return 0; + } + + return real_connect(sockfd, addr, addrlen); +} + +#endif /* __linux__ && RTLD_NEXT */ diff --git a/tests/virvsocktest.c b/tests/virvsocktest.c new file mode 100644 index 0000000000..2571db0107 --- /dev/null +++ b/tests/virvsocktest.c @@ -0,0 +1,133 @@ +/* + * Copyright (C) 2026 Virtuozzo International GmbH + * + * 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 + * . + */ + +#include + +#include + +#include "testutils.h" +#include "virvsock.h" +#include "virerror.h" +#include "virfile.h" +#include "virlog.h" + +#define VIR_FROM_THIS VIR_FROM_NONE + +VIR_LOG_INIT("tests.vsocktest"); + +static int +testVsockConnectAddr(const void *opaque G_GNUC_UNUSED) +{ + const unsigned int cid =3D 42; + const unsigned int port =3D 1234; + g_autofree char *cidStr =3D g_strdup_printf("%u", cid); + g_autofree char *portStr =3D g_strdup_printf("%u", port); + VIR_AUTOCLOSE fd =3D -1; + + /* The mock fails the connect unless production reaches it with exactly + * this cid/port, so a successful connect is the assertion. */ + g_setenv("LIBVIRT_VSOCK_MOCK_EXPECT_CID", cidStr, true); + g_setenv("LIBVIRT_VSOCK_MOCK_EXPECT_PORT", portStr, true); + + fd =3D virVsockConnectQuiet(cid, port); + + g_unsetenv("LIBVIRT_VSOCK_MOCK_EXPECT_CID"); + g_unsetenv("LIBVIRT_VSOCK_MOCK_EXPECT_PORT"); + + if (fd < 0) { + fprintf(stderr, "virVsockConnectQuiet failed: wrong cid/port reach= ed the kernel\n"); + return -1; + } + + return 0; +} + + +static int +testVsockConnectTimeout(const void *opaque G_GNUC_UNUSED) +{ + g_autofree char *timeoutStr =3D + g_strdup_printf("%lld", VIR_VSOCK_CONNECT_TIMEOUT_MS * 1000LL); + VIR_AUTOCLOSE fd =3D -1; + + /* The mock fails the connect unless the timeout was applied via + * setsockopt() beforehand. */ + g_setenv("LIBVIRT_VSOCK_MOCK_EXPECT_TIMEOUT_US", timeoutStr, true); + + fd =3D virVsockConnectQuiet(VIR_VSOCK_GUEST_CID_MIN, 1234); + + g_unsetenv("LIBVIRT_VSOCK_MOCK_EXPECT_TIMEOUT_US"); + + if (fd < 0) { + fprintf(stderr, "virVsockConnectQuiet failed: connect timeout not = applied\n"); + return -1; + } + + return 0; +} + + +static int +testVsockConnectErrno(const void *opaque G_GNUC_UNUSED) +{ + g_autofree char *errstr =3D g_strdup_printf("%d", ECONNREFUSED); + int fd; + + g_setenv("LIBVIRT_VSOCK_MOCK_CONNECT_ERRNO", errstr, true); + + virResetLastError(); + errno =3D 0; + fd =3D virVsockConnectQuiet(VIR_VSOCK_GUEST_CID_MIN, 1234); + g_unsetenv("LIBVIRT_VSOCK_MOCK_CONNECT_ERRNO"); + + if (fd !=3D -1) { + VIR_FORCE_CLOSE(fd); + fprintf(stderr, "virVsockConnectQuiet should have failed\n"); + return -1; + } + + if (errno !=3D ECONNREFUSED) { + fprintf(stderr, "expected errno %d, got %d\n", ECONNREFUSED, errno= ); + return -1; + } + + if (virGetLastError()) { + fprintf(stderr, "virVsockConnectQuiet reported a libvirt error\n"); + return -1; + } + + return 0; +} + + +static int +mymain(void) +{ + int ret =3D 0; + + if (virTestRun("vsock connect address", testVsockConnectAddr, NULL) < = 0) + ret =3D -1; + if (virTestRun("vsock connect timeout", testVsockConnectTimeout, NULL)= < 0) + ret =3D -1; + if (virTestRun("vsock connect errno preserved", testVsockConnectErrno,= NULL) < 0) + ret =3D -1; + + return ret =3D=3D 0 ? EXIT_SUCCESS : EXIT_FAILURE; +} + +VIR_TEST_MAIN_PRELOAD(mymain, VIR_TEST_MOCK("virvsock")) --=20 2.54.0