From nobody Fri May 3 13:09:24 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 152517279228420.558184647339885; Tue, 1 May 2018 04:06:32 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx09.intmail.prod.int.phx2.redhat.com [10.5.11.24]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7F2683188CE2; Tue, 1 May 2018 11:06:30 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 1F8F830012A0; Tue, 1 May 2018 11:06:30 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id D5FA04CAA8; Tue, 1 May 2018 11:06:27 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w41B6PHI013351 for ; Tue, 1 May 2018 07:06:25 -0400 Received: by smtp.corp.redhat.com (Postfix) id 237012166BDA; Tue, 1 May 2018 11:06:25 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.41]) by smtp.corp.redhat.com (Postfix) with ESMTP id 6A2852166BAD; Tue, 1 May 2018 11:06:24 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Tue, 1 May 2018 12:06:22 +0100 Message-Id: <20180501110623.28330-2-berrange@redhat.com> In-Reply-To: <20180501110623.28330-1-berrange@redhat.com> References: <20180501110623.28330-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-loop: libvir-list@redhat.com Cc: Andrea Bolognani Subject: [libvirt] [PATCH 1/2] tests: merge code for UNIX and TCP socket testing X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.84 on 10.5.11.24 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.41]); Tue, 01 May 2018 11:06:31 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 The test code for UNIX and TCP sockets will need to be rewritten and extended later, and will benefit from code sharing. Signed-off-by: Daniel P. Berrang=C3=A9 Reviewed-by: Andrea Bolognani --- tests/virnetsockettest.c | 120 ++++++++++++++++++++-----------------------= ---- 1 file changed, 51 insertions(+), 69 deletions(-) diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index 9f9a243484..e463d432ff 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -116,38 +116,67 @@ checkProtocols(bool *hasIPv4, bool *hasIPv6, } =20 =20 -struct testTCPData { +struct testSocketData { const char *lnode; int port; const char *cnode; }; =20 -static int testSocketTCPAccept(const void *opaque) +static int testSocketAccept(const void *opaque) { virNetSocketPtr *lsock =3D NULL; /* Listen socket */ size_t nlsock =3D 0, i; virNetSocketPtr ssock =3D NULL; /* Server socket */ virNetSocketPtr csock =3D NULL; /* Client socket */ - const struct testTCPData *data =3D opaque; + const struct testSocketData *data =3D opaque; int ret =3D -1; char portstr[100]; + char *tmpdir =3D NULL; + char *path =3D NULL; + char template[] =3D "/tmp/libvirt_XXXXXX"; =20 - snprintf(portstr, sizeof(portstr), "%d", data->port); + if (!data) { + virNetSocketPtr usock; + tmpdir =3D mkdtemp(template); + if (tmpdir =3D=3D NULL) { + VIR_WARN("Failed to create temporary directory"); + goto cleanup; + } + if (virAsprintf(&path, "%s/test.sock", tmpdir) < 0) + goto cleanup; =20 - if (virNetSocketNewListenTCP(data->lnode, portstr, - AF_UNSPEC, - &lsock, &nlsock) < 0) - goto cleanup; + if (virNetSocketNewListenUNIX(path, 0700, -1, getegid(), &usock) <= 0) + goto cleanup; + + if (VIR_ALLOC_N(lsock, 1) < 0) { + virObjectUnref(usock); + goto cleanup; + } + + lsock[0] =3D usock; + nlsock =3D 1; + } else { + snprintf(portstr, sizeof(portstr), "%d", data->port); + if (virNetSocketNewListenTCP(data->lnode, portstr, + AF_UNSPEC, + &lsock, &nlsock) < 0) + goto cleanup; + } =20 for (i =3D 0; i < nlsock; i++) { if (virNetSocketListen(lsock[i], 0) < 0) goto cleanup; } =20 - if (virNetSocketNewConnectTCP(data->cnode, portstr, - AF_UNSPEC, - &csock) < 0) - goto cleanup; + if (!data) { + if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0) + goto cleanup; + } else { + if (virNetSocketNewConnectTCP(data->cnode, portstr, + AF_UNSPEC, + &csock) < 0) + goto cleanup; + } =20 virObjectUnref(csock); =20 @@ -171,62 +200,15 @@ static int testSocketTCPAccept(const void *opaque) for (i =3D 0; i < nlsock; i++) virObjectUnref(lsock[i]); VIR_FREE(lsock); - return ret; -} -#endif - - -#ifndef WIN32 -static int testSocketUNIXAccept(const void *data ATTRIBUTE_UNUSED) -{ - virNetSocketPtr lsock =3D NULL; /* Listen socket */ - virNetSocketPtr ssock =3D NULL; /* Server socket */ - virNetSocketPtr csock =3D NULL; /* Client socket */ - int ret =3D -1; - - char *path =3D NULL; - char *tmpdir; - char template[] =3D "/tmp/libvirt_XXXXXX"; - - tmpdir =3D mkdtemp(template); - if (tmpdir =3D=3D NULL) { - VIR_WARN("Failed to create temporary directory"); - goto cleanup; - } - if (virAsprintf(&path, "%s/test.sock", tmpdir) < 0) - goto cleanup; - - if (virNetSocketNewListenUNIX(path, 0700, -1, getegid(), &lsock) < 0) - goto cleanup; - - if (virNetSocketListen(lsock, 0) < 0) - goto cleanup; - - if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0) - goto cleanup; - - virObjectUnref(csock); - - if (virNetSocketAccept(lsock, &ssock) !=3D -1) { - char c =3D 'a'; - if (virNetSocketWrite(ssock, &c, 1) !=3D -1) { - VIR_DEBUG("Unexpected client socket present"); - goto cleanup; - } - } - - ret =3D 0; - - cleanup: VIR_FREE(path); - virObjectUnref(lsock); - virObjectUnref(ssock); if (tmpdir) rmdir(tmpdir); return ret; } +#endif =20 =20 +#ifndef WIN32 static int testSocketUNIXAddrs(const void *data ATTRIBUTE_UNUSED) { virNetSocketPtr lsock =3D NULL; /* Listen socket */ @@ -456,28 +438,28 @@ mymain(void) } =20 if (hasIPv4) { - struct testTCPData tcpData =3D { "127.0.0.1", freePort, "127.0.0.1= " }; - if (virTestRun("Socket TCP/IPv4 Accept", testSocketTCPAccept, &tcp= Data) < 0) + struct testSocketData tcpData =3D { "127.0.0.1", freePort, "127.0.= 0.1" }; + if (virTestRun("Socket TCP/IPv4 Accept", testSocketAccept, &tcpDat= a) < 0) ret =3D -1; } if (hasIPv6) { - struct testTCPData tcpData =3D { "::1", freePort, "::1" }; - if (virTestRun("Socket TCP/IPv6 Accept", testSocketTCPAccept, &tcp= Data) < 0) + struct testSocketData tcpData =3D { "::1", freePort, "::1" }; + if (virTestRun("Socket TCP/IPv6 Accept", testSocketAccept, &tcpDat= a) < 0) ret =3D -1; } if (hasIPv6 && hasIPv4) { - struct testTCPData tcpData =3D { NULL, freePort, "127.0.0.1" }; - if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketTCPAccept,= &tcpData) < 0) + struct testSocketData tcpData =3D { NULL, freePort, "127.0.0.1" }; + if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketAccept, &t= cpData) < 0) ret =3D -1; =20 tcpData.cnode =3D "::1"; - if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketTCPAccept,= &tcpData) < 0) + if (virTestRun("Socket TCP/IPv4+IPv6 Accept", testSocketAccept, &t= cpData) < 0) ret =3D -1; } #endif =20 #ifndef WIN32 - if (virTestRun("Socket UNIX Accept", testSocketUNIXAccept, NULL) < 0) + if (virTestRun("Socket UNIX Accept", testSocketAccept, NULL) < 0) ret =3D -1; =20 if (virTestRun("Socket UNIX Addrs", testSocketUNIXAddrs, NULL) < 0) --=20 2.14.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list From nobody Fri May 3 13:09:24 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) client-ip=209.132.183.28; envelope-from=libvir-list-bounces@redhat.com; helo=mx1.redhat.com; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of redhat.com designates 209.132.183.28 as permitted sender) smtp.mailfrom=libvir-list-bounces@redhat.com; dmarc=pass(p=none dis=none) header.from=redhat.com Return-Path: Received: from mx1.redhat.com (mx1.redhat.com [209.132.183.28]) by mx.zohomail.com with SMTPS id 1525172808869441.5945365515789; Tue, 1 May 2018 04:06:48 -0700 (PDT) Received: from smtp.corp.redhat.com (int-mx05.intmail.prod.int.phx2.redhat.com [10.5.11.15]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 8C5824E90C; Tue, 1 May 2018 11:06:47 +0000 (UTC) Received: from colo-mx.corp.redhat.com (colo-mx02.intmail.prod.int.phx2.redhat.com [10.5.11.21]) by smtp.corp.redhat.com (Postfix) with ESMTPS id 33838808B9; Tue, 1 May 2018 11:06:47 +0000 (UTC) Received: from lists01.pubmisc.prod.ext.phx2.redhat.com (lists01.pubmisc.prod.ext.phx2.redhat.com [10.5.19.33]) by colo-mx.corp.redhat.com (Postfix) with ESMTP id B64DA4CA96; Tue, 1 May 2018 11:06:46 +0000 (UTC) Received: from smtp.corp.redhat.com (int-mx06.intmail.prod.int.rdu2.redhat.com [10.11.54.6]) by lists01.pubmisc.prod.ext.phx2.redhat.com (8.13.8/8.13.8) with ESMTP id w41B6QSP013361 for ; Tue, 1 May 2018 07:06:26 -0400 Received: by smtp.corp.redhat.com (Postfix) id E684D2166BCC; Tue, 1 May 2018 11:06:25 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.41]) by smtp.corp.redhat.com (Postfix) with ESMTP id 57BFE2166BAD; Tue, 1 May 2018 11:06:25 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: libvir-list@redhat.com Date: Tue, 1 May 2018 12:06:23 +0100 Message-Id: <20180501110623.28330-3-berrange@redhat.com> In-Reply-To: <20180501110623.28330-1-berrange@redhat.com> References: <20180501110623.28330-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.6 X-loop: libvir-list@redhat.com Cc: Andrea Bolognani Subject: [libvirt] [PATCH 2/2] tests: rewrite socket to do something sensible and reliable X-BeenThere: libvir-list@redhat.com X-Mailman-Version: 2.1.12 Precedence: junk List-Id: Development discussions about the libvirt library & tools List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Content-Type: text/plain; charset="utf-8" Content-Transfer-Encoding: quoted-printable Sender: libvir-list-bounces@redhat.com Errors-To: libvir-list-bounces@redhat.com X-Scanned-By: MIMEDefang 2.79 on 10.5.11.15 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.5.110.38]); Tue, 01 May 2018 11:06:48 +0000 (UTC) X-ZohoMail: RSF_0 Z_629925259 SPT_0 The current socket test is rather crazy in that it sets up a server listening for sockets and then runs a client connect call, relying on the fact that the kernel will accept this despite the application not having called accept() yet. It then closes the client socket and calls accept() on the server. On Linux accept() will always see that the client has gone and so skip the rest of the code. On FreeBSD, however, the accept sometimes succeeds, causing us to then go into code that attempts to read and write to the client which will fail aborting the test. The accept() never succeeds on FreeBSD guests with a single CPU, but as you add more CPUs, accept() becomes more and more likely to succeed, giving a 100% failure rate for the test when using 8 CPUs. This completely rewrites the test so that it is avoids this designed in race condition. We simply spawn a background thread to act as the client, which will read a byte from the server and write it back again. The main thread can now properly listen and accept the client in a synchronous manner avoiding any races. Signed-off-by: Daniel P. Berrang=C3=A9 --- tests/virnetsockettest.c | 138 +++++++++++++++++++++++++++++++++++++++----= ---- 1 file changed, 117 insertions(+), 21 deletions(-) diff --git a/tests/virnetsockettest.c b/tests/virnetsockettest.c index e463d432ff..bdc9f5b366 100644 --- a/tests/virnetsockettest.c +++ b/tests/virnetsockettest.c @@ -115,6 +115,56 @@ checkProtocols(bool *hasIPv4, bool *hasIPv6, return ret; } =20 +struct testClientData { + const char *path; + const char *cnode; + const char *portstr; +}; + +static void +testSocketClient(void *opaque) +{ + struct testClientData *data =3D opaque; + char c; + virNetSocketPtr csock =3D NULL; + + if (data->path) { + if (virNetSocketNewConnectUNIX(data->path, false, + NULL, &csock) < 0) + return; + } else { + if (virNetSocketNewConnectTCP(data->cnode, data->portstr, + AF_UNSPEC, + &csock) < 0) + return; + } + + virNetSocketSetBlocking(csock, true); + + if (virNetSocketRead(csock, &c, 1) !=3D 1) { + VIR_DEBUG("Cannot read from server"); + goto done; + } + if (virNetSocketWrite(csock, &c, 1) !=3D 1) { + VIR_DEBUG("Cannot write to server"); + goto done; + } + + done: + virObjectUnref(csock); +} + + +static void +testSocketIncoming(virNetSocketPtr sock, + int events ATTRIBUTE_UNUSED, + void *opaque) +{ + virNetSocketPtr *retsock =3D opaque; + VIR_DEBUG("Incoming sock=3D%p events=3D%d\n", sock, events); + *retsock =3D sock; +} + =20 struct testSocketData { const char *lnode; @@ -122,18 +172,24 @@ struct testSocketData { const char *cnode; }; =20 -static int testSocketAccept(const void *opaque) + +static int +testSocketAccept(const void *opaque) { virNetSocketPtr *lsock =3D NULL; /* Listen socket */ size_t nlsock =3D 0, i; virNetSocketPtr ssock =3D NULL; /* Server socket */ - virNetSocketPtr csock =3D NULL; /* Client socket */ + virNetSocketPtr rsock =3D NULL; /* Server from poll */ const struct testSocketData *data =3D opaque; int ret =3D -1; char portstr[100]; char *tmpdir =3D NULL; char *path =3D NULL; char template[] =3D "/tmp/libvirt_XXXXXX"; + virThread th; + struct testClientData cdata =3D { 0 }; + bool goodsock =3D false; + char a =3D 'a', b =3D '\0'; =20 if (!data) { virNetSocketPtr usock; @@ -155,50 +211,88 @@ static int testSocketAccept(const void *opaque) =20 lsock[0] =3D usock; nlsock =3D 1; + + cdata.path =3D path; } else { snprintf(portstr, sizeof(portstr), "%d", data->port); if (virNetSocketNewListenTCP(data->lnode, portstr, AF_UNSPEC, &lsock, &nlsock) < 0) goto cleanup; + + cdata.cnode =3D data->cnode; + cdata.portstr =3D portstr; } =20 for (i =3D 0; i < nlsock; i++) { if (virNetSocketListen(lsock[i], 0) < 0) goto cleanup; - } =20 - if (!data) { - if (virNetSocketNewConnectUNIX(path, false, NULL, &csock) < 0) - goto cleanup; - } else { - if (virNetSocketNewConnectTCP(data->cnode, portstr, - AF_UNSPEC, - &csock) < 0) + if (virNetSocketAddIOCallback(lsock[i], + VIR_EVENT_HANDLE_READABLE, + testSocketIncoming, + &rsock, + NULL) < 0) { goto cleanup; + } } =20 - virObjectUnref(csock); + if (virThreadCreate(&th, true, + testSocketClient, + &cdata) < 0) + goto cleanup; + + while (rsock =3D=3D NULL) + virEventRunDefaultImpl(); =20 for (i =3D 0; i < nlsock; i++) { - if (virNetSocketAccept(lsock[i], &ssock) !=3D -1 && ssock) { - char c =3D 'a'; - if (virNetSocketWrite(ssock, &c, 1) !=3D -1 && - virNetSocketRead(ssock, &c, 1) !=3D -1) { - VIR_DEBUG("Unexpected client socket present"); - goto cleanup; - } + if (lsock[i] =3D=3D rsock) { + goodsock =3D true; + break; } - virObjectUnref(ssock); - ssock =3D NULL; } =20 + if (!goodsock) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + "Unexpected server socket seen"); + goto join; + } + + if (virNetSocketAccept(rsock, &ssock) < 0) + goto join; + + if (!ssock) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + "Client went away unexpectedly"); + goto join; + } + + virNetSocketSetBlocking(ssock, true); + + if (virNetSocketWrite(ssock, &a, 1) < 0 || + virNetSocketRead(ssock, &b, 1) < 0) + goto join; + + if (a !=3D b) { + virReportError(VIR_ERR_INTERNAL_ERROR, + "Bad data received '%x' !=3D '%x'", a, b); + goto join; + } + virObjectUnref(ssock); + ssock =3D NULL; + ret =3D 0; =20 + join: + virThreadJoin(&th); + cleanup: virObjectUnref(ssock); - for (i =3D 0; i < nlsock; i++) + for (i =3D 0; i < nlsock; i++) { + virNetSocketRemoveIOCallback(lsock[i]); + virNetSocketClose(lsock[i]); virObjectUnref(lsock[i]); + } VIR_FREE(lsock); VIR_FREE(path); if (tmpdir) @@ -431,6 +525,8 @@ mymain(void) =20 signal(SIGPIPE, SIG_IGN); =20 + virEventRegisterDefaultImpl(); + #ifdef HAVE_IFADDRS_H if (checkProtocols(&hasIPv4, &hasIPv6, &freePort) < 0) { fprintf(stderr, "Cannot identify IPv4/6 availability\n"); --=20 2.14.3 -- libvir-list mailing list libvir-list@redhat.com https://www.redhat.com/mailman/listinfo/libvir-list