From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520885742062834.7416269449741; Mon, 12 Mar 2018 13:15:42 -0700 (PDT) Received: from localhost ([::1]:34407 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTr2-0005X9-AL for importer@patchew.org; Mon, 12 Mar 2018 16:15:32 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39699) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp0-0004FK-C1 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTow-00074m-8G for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:34008 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evTow-00074L-3R for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:22 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 5BA2E401D786; Mon, 12 Mar 2018 20:13:17 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 3A6B01102E26; Mon, 12 Mar 2018 20:13:16 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:12:57 +0000 Message-Id: <20180312201305.16972-2-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 12 Mar 2018 20:13:17 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.6]); Mon, 12 Mar 2018 20:13:17 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 1/9] char: don't silently skip tn3270 protocol init when TLS is enabled X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" Even if common tn3270 implementations do not support TLS, it is trivial to have them proxied over a proxy like stunnel which adds TLS at the sockets layer. We should thus not silently skip tn3270 protocol initialization when TLS is enabled. Reviewed-by: Eric Blake Acked-by: Cornelia Huck Signed-off-by: Daniel P. Berrange --- chardev/char-socket.c | 3 +-- 1 file changed, 1 insertion(+), 2 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index a220803c01..1a371b91ac 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -663,8 +663,7 @@ static void tcp_chr_tls_handshake(QIOTask *task, if (qio_task_propagate_error(task, NULL)) { tcp_chr_disconnect(chr); } else { - /* tn3270 does not support TLS yet */ - if (s->do_telnetopt && !s->is_tn3270) { + if (s->do_telnetopt) { tcp_chr_telnet_init(chr); } else { tcp_chr_connect(chr); --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520886254643270.59561362994236; Mon, 12 Mar 2018 13:24:14 -0700 (PDT) Received: from localhost ([::1]:34464 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTzR-0003lk-Pu for importer@patchew.org; Mon, 12 Mar 2018 16:24:13 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39700) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp0-0004FL-Bz for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTow-00074w-9I for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43324 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evTow-00074N-3I for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:22 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id CA16DBD9E; Mon, 12 Mar 2018 20:13:18 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 8C5081102E25; Mon, 12 Mar 2018 20:13:17 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:12:58 +0000 Message-Id: <20180312201305.16972-3-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Mon, 12 Mar 2018 20:13:18 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Mon, 12 Mar 2018 20:13:18 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 2/9] cutils: add qemu_strtoi & qemu_strtoui parsers for int/unsigned int types X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" There are qemu_strtoNN functions for various sized integers. This adds two more for plain int & unsigned int types, with suitable range checking. Reviewed-by: Eric Blake Reviewed-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- include/qemu/cutils.h | 4 + tests/test-cutils.c | 657 ++++++++++++++++++++++++++++++++++++++++++++++= ++++ util/cutils.c | 108 +++++++++ 3 files changed, 769 insertions(+) diff --git a/include/qemu/cutils.h b/include/qemu/cutils.h index f0878eaafa..a663340b23 100644 --- a/include/qemu/cutils.h +++ b/include/qemu/cutils.h @@ -126,6 +126,10 @@ time_t mktimegm(struct tm *tm); int qemu_fdatasync(int fd); int fcntl_setfl(int fd, int flag); int qemu_parse_fd(const char *param); +int qemu_strtoi(const char *nptr, const char **endptr, int base, + int *result); +int qemu_strtoui(const char *nptr, const char **endptr, int base, + unsigned int *result); int qemu_strtol(const char *nptr, const char **endptr, int base, long *result); int qemu_strtoul(const char *nptr, const char **endptr, int base, diff --git a/tests/test-cutils.c b/tests/test-cutils.c index f64a49b7fb..64a489c2e9 100644 --- a/tests/test-cutils.c +++ b/tests/test-cutils.c @@ -223,6 +223,583 @@ static void test_parse_uint_full_correct(void) g_assert_cmpint(i, =3D=3D, 123); } =20 +static void test_qemu_strtoi_correct(void) +{ + const char *str =3D "12345 foo"; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 12345); + g_assert(endptr =3D=3D str + 5); +} + +static void test_qemu_strtoi_null(void) +{ + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D NULL); +} + +static void test_qemu_strtoi_empty(void) +{ + const char *str =3D ""; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D str); +} + +static void test_qemu_strtoi_whitespace(void) +{ + const char *str =3D " \t "; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D str); +} + +static void test_qemu_strtoi_invalid(void) +{ + const char *str =3D " xxxx \t abc"; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D str); +} + +static void test_qemu_strtoi_trailing(void) +{ + const char *str =3D "123xxx"; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 123); + g_assert(endptr =3D=3D str + 3); +} + +static void test_qemu_strtoi_octal(void) +{ + const char *str =3D "0123"; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 8, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 0123); + g_assert(endptr =3D=3D str + strlen(str)); + + res =3D 999; + endptr =3D &f; + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 0123); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoi_decimal(void) +{ + const char *str =3D "0123"; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 10, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 123); + g_assert(endptr =3D=3D str + strlen(str)); + + str =3D "123"; + res =3D 999; + endptr =3D &f; + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 123); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoi_hex(void) +{ + const char *str =3D "0123"; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 16, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 0x123); + g_assert(endptr =3D=3D str + strlen(str)); + + str =3D "0x123"; + res =3D 999; + endptr =3D &f; + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 0x123); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoi_max(void) +{ + char *str =3D g_strdup_printf("%d", INT_MAX); + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, INT_MAX); + g_assert(endptr =3D=3D str + strlen(str)); + g_free(str); +} + +static void test_qemu_strtoi_overflow(void) +{ + char *str =3D g_strdup_printf("%lld", (long long)INT_MAX + 1ll); + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -ERANGE); + g_assert_cmpint(res, =3D=3D, INT_MAX); + g_assert(endptr =3D=3D str + strlen(str)); + g_free(str); +} + +static void test_qemu_strtoi_underflow(void) +{ + char *str =3D g_strdup_printf("%lld", (long long)INT_MIN - 1ll); + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -ERANGE); + g_assert_cmpint(res, =3D=3D, INT_MIN); + g_assert(endptr =3D=3D str + strlen(str)); + g_free(str); +} + +static void test_qemu_strtoi_negative(void) +{ + const char *str =3D " \t -321"; + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, -321); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoi_full_correct(void) +{ + const char *str =3D "123"; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, 123); +} + +static void test_qemu_strtoi_full_null(void) +{ + char f =3D 'X'; + const char *endptr =3D &f; + int res =3D 999; + int err; + + err =3D qemu_strtoi(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D NULL); +} + +static void test_qemu_strtoi_full_empty(void) +{ + const char *str =3D ""; + int res =3D 999L; + int err; + + err =3D qemu_strtoi(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); +} + +static void test_qemu_strtoi_full_negative(void) +{ + const char *str =3D " \t -321"; + int res =3D 999; + int err; + + err =3D qemu_strtoi(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, -321); +} + +static void test_qemu_strtoi_full_trailing(void) +{ + const char *str =3D "123xxx"; + int res; + int err; + + err =3D qemu_strtoi(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); +} + +static void test_qemu_strtoi_full_max(void) +{ + char *str =3D g_strdup_printf("%d", INT_MAX); + int res; + int err; + + err =3D qemu_strtoi(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpint(res, =3D=3D, INT_MAX); + g_free(str); +} + +static void test_qemu_strtoui_correct(void) +{ + const char *str =3D "12345 foo"; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, 12345); + g_assert(endptr =3D=3D str + 5); +} + +static void test_qemu_strtoui_null(void) +{ + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(NULL, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D NULL); +} + +static void test_qemu_strtoui_empty(void) +{ + const char *str =3D ""; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D str); +} + +static void test_qemu_strtoui_whitespace(void) +{ + const char *str =3D " \t "; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D str); +} + +static void test_qemu_strtoui_invalid(void) +{ + const char *str =3D " xxxx \t abc"; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); + g_assert(endptr =3D=3D str); +} + +static void test_qemu_strtoui_trailing(void) +{ + const char *str =3D "123xxx"; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, 123); + g_assert(endptr =3D=3D str + 3); +} + +static void test_qemu_strtoui_octal(void) +{ + const char *str =3D "0123"; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 8, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, 0123); + g_assert(endptr =3D=3D str + strlen(str)); + + res =3D 999; + endptr =3D &f; + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, 0123); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoui_decimal(void) +{ + const char *str =3D "0123"; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 10, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, 123); + g_assert(endptr =3D=3D str + strlen(str)); + + str =3D "123"; + res =3D 999; + endptr =3D &f; + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, 123); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoui_hex(void) +{ + const char *str =3D "0123"; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 16, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmphex(res, =3D=3D, 0x123); + g_assert(endptr =3D=3D str + strlen(str)); + + str =3D "0x123"; + res =3D 999; + endptr =3D &f; + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmphex(res, =3D=3D, 0x123); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoui_max(void) +{ + char *str =3D g_strdup_printf("%u", UINT_MAX); + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmphex(res, =3D=3D, UINT_MAX); + g_assert(endptr =3D=3D str + strlen(str)); + g_free(str); +} + +static void test_qemu_strtoui_overflow(void) +{ + char *str =3D g_strdup_printf("%lld", (long long)UINT_MAX + 1ll); + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -ERANGE); + g_assert_cmphex(res, =3D=3D, UINT_MAX); + g_assert(endptr =3D=3D str + strlen(str)); + g_free(str); +} + +static void test_qemu_strtoui_underflow(void) +{ + char *str =3D g_strdup_printf("%lld", (long long)INT_MIN - 1ll); + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, -ERANGE); + g_assert_cmpuint(res, =3D=3D, (unsigned int)-1); + g_assert(endptr =3D=3D str + strlen(str)); + g_free(str); +} + +static void test_qemu_strtoui_negative(void) +{ + const char *str =3D " \t -321"; + char f =3D 'X'; + const char *endptr =3D &f; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, &endptr, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, (unsigned int)-321); + g_assert(endptr =3D=3D str + strlen(str)); +} + +static void test_qemu_strtoui_full_correct(void) +{ + const char *str =3D "123"; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, 123); +} + +static void test_qemu_strtoui_full_null(void) +{ + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(NULL, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); +} + +static void test_qemu_strtoui_full_empty(void) +{ + const char *str =3D ""; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); +} +static void test_qemu_strtoui_full_negative(void) +{ + const char *str =3D " \t -321"; + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, NULL, 0, &res); + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmpuint(res, =3D=3D, (unsigned int)-321); +} + +static void test_qemu_strtoui_full_trailing(void) +{ + const char *str =3D "123xxx"; + unsigned int res; + int err; + + err =3D qemu_strtoui(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, -EINVAL); +} + +static void test_qemu_strtoui_full_max(void) +{ + char *str =3D g_strdup_printf("%u", UINT_MAX); + unsigned int res =3D 999; + int err; + + err =3D qemu_strtoui(str, NULL, 0, &res); + + g_assert_cmpint(err, =3D=3D, 0); + g_assert_cmphex(res, =3D=3D, UINT_MAX); + g_free(str); +} + static void test_qemu_strtol_correct(void) { const char *str =3D "12345 foo"; @@ -1612,6 +2189,86 @@ int main(int argc, char **argv) g_test_add_func("/cutils/parse_uint_full/correct", test_parse_uint_full_correct); =20 + /* qemu_strtoi() tests */ + g_test_add_func("/cutils/qemu_strtoi/correct", + test_qemu_strtoi_correct); + g_test_add_func("/cutils/qemu_strtoi/null", + test_qemu_strtoi_null); + g_test_add_func("/cutils/qemu_strtoi/empty", + test_qemu_strtoi_empty); + g_test_add_func("/cutils/qemu_strtoi/whitespace", + test_qemu_strtoi_whitespace); + g_test_add_func("/cutils/qemu_strtoi/invalid", + test_qemu_strtoi_invalid); + g_test_add_func("/cutils/qemu_strtoi/trailing", + test_qemu_strtoi_trailing); + g_test_add_func("/cutils/qemu_strtoi/octal", + test_qemu_strtoi_octal); + g_test_add_func("/cutils/qemu_strtoi/decimal", + test_qemu_strtoi_decimal); + g_test_add_func("/cutils/qemu_strtoi/hex", + test_qemu_strtoi_hex); + g_test_add_func("/cutils/qemu_strtoi/max", + test_qemu_strtoi_max); + g_test_add_func("/cutils/qemu_strtoi/overflow", + test_qemu_strtoi_overflow); + g_test_add_func("/cutils/qemu_strtoi/underflow", + test_qemu_strtoi_underflow); + g_test_add_func("/cutils/qemu_strtoi/negative", + test_qemu_strtoi_negative); + g_test_add_func("/cutils/qemu_strtoi_full/correct", + test_qemu_strtoi_full_correct); + g_test_add_func("/cutils/qemu_strtoi_full/null", + test_qemu_strtoi_full_null); + g_test_add_func("/cutils/qemu_strtoi_full/empty", + test_qemu_strtoi_full_empty); + g_test_add_func("/cutils/qemu_strtoi_full/negative", + test_qemu_strtoi_full_negative); + g_test_add_func("/cutils/qemu_strtoi_full/trailing", + test_qemu_strtoi_full_trailing); + g_test_add_func("/cutils/qemu_strtoi_full/max", + test_qemu_strtoi_full_max); + + /* qemu_strtoui() tests */ + g_test_add_func("/cutils/qemu_strtoui/correct", + test_qemu_strtoui_correct); + g_test_add_func("/cutils/qemu_strtoui/null", + test_qemu_strtoui_null); + g_test_add_func("/cutils/qemu_strtoui/empty", + test_qemu_strtoui_empty); + g_test_add_func("/cutils/qemu_strtoui/whitespace", + test_qemu_strtoui_whitespace); + g_test_add_func("/cutils/qemu_strtoui/invalid", + test_qemu_strtoui_invalid); + g_test_add_func("/cutils/qemu_strtoui/trailing", + test_qemu_strtoui_trailing); + g_test_add_func("/cutils/qemu_strtoui/octal", + test_qemu_strtoui_octal); + g_test_add_func("/cutils/qemu_strtoui/decimal", + test_qemu_strtoui_decimal); + g_test_add_func("/cutils/qemu_strtoui/hex", + test_qemu_strtoui_hex); + g_test_add_func("/cutils/qemu_strtoui/max", + test_qemu_strtoui_max); + g_test_add_func("/cutils/qemu_strtoui/overflow", + test_qemu_strtoui_overflow); + g_test_add_func("/cutils/qemu_strtoui/underflow", + test_qemu_strtoui_underflow); + g_test_add_func("/cutils/qemu_strtoui/negative", + test_qemu_strtoui_negative); + g_test_add_func("/cutils/qemu_strtoui_full/correct", + test_qemu_strtoui_full_correct); + g_test_add_func("/cutils/qemu_strtoui_full/null", + test_qemu_strtoui_full_null); + g_test_add_func("/cutils/qemu_strtoui_full/empty", + test_qemu_strtoui_full_empty); + g_test_add_func("/cutils/qemu_strtoui_full/negative", + test_qemu_strtoui_full_negative); + g_test_add_func("/cutils/qemu_strtoui_full/trailing", + test_qemu_strtoui_full_trailing); + g_test_add_func("/cutils/qemu_strtoui_full/max", + test_qemu_strtoui_full_max); + /* qemu_strtol() tests */ g_test_add_func("/cutils/qemu_strtol/correct", test_qemu_strtol_correct); diff --git a/util/cutils.c b/util/cutils.c index b33ede83d1..774d5f7362 100644 --- a/util/cutils.c +++ b/util/cutils.c @@ -297,6 +297,114 @@ static int check_strtox_error(const char *nptr, char = *ep, return -libc_errno; } =20 +/** + * Convert string @nptr to an integer, and store it in @result. + * + * This is a wrapper around strtol() that is harder to misuse. + * Semantics of @nptr, @endptr, @base match strtol() with differences + * noted below. + * + * @nptr may be null, and no conversion is performed then. + * + * If no conversion is performed, store @nptr in *@endptr and return + * -EINVAL. + * + * If @endptr is null, and the string isn't fully converted, return + * -EINVAL. This is the case when the pointer that would be stored in + * a non-null @endptr points to a character other than '\0'. + * + * If the conversion overflows @result, store INT_MAX in @result, + * and return -ERANGE. + * + * If the conversion underflows @result, store INT_MIN in @result, + * and return -ERANGE. + * + * Else store the converted value in @result, and return zero. + */ +int qemu_strtoi(const char *nptr, const char **endptr, int base, + int *result) +{ + char *ep; + long lresult; + + if (!nptr) { + if (endptr) { + *endptr =3D nptr; + } + return -EINVAL; + } + + errno =3D 0; + lresult =3D strtol(nptr, &ep, base); + if (lresult < INT_MIN) { + *result =3D INT_MIN; + errno =3D ERANGE; + } else if (lresult > INT_MAX) { + *result =3D INT_MAX; + errno =3D ERANGE; + } else { + *result =3D lresult; + } + return check_strtox_error(nptr, ep, endptr, errno); +} + +/** + * Convert string @nptr to an unsigned integer, and store it in @result. + * + * This is a wrapper around strtoul() that is harder to misuse. + * Semantics of @nptr, @endptr, @base match strtoul() with differences + * noted below. + * + * @nptr may be null, and no conversion is performed then. + * + * If no conversion is performed, store @nptr in *@endptr and return + * -EINVAL. + * + * If @endptr is null, and the string isn't fully converted, return + * -EINVAL. This is the case when the pointer that would be stored in + * a non-null @endptr points to a character other than '\0'. + * + * If the conversion overflows @result, store UINT_MAX in @result, + * and return -ERANGE. + * + * Else store the converted value in @result, and return zero. + * + * Note that a number with a leading minus sign gets converted without + * the minus sign, checked for overflow (see above), then negated (in + * @result's type). This is exactly how strtoul() works. + */ +int qemu_strtoui(const char *nptr, const char **endptr, int base, + unsigned int *result) +{ + char *ep; + long lresult; + + if (!nptr) { + if (endptr) { + *endptr =3D nptr; + } + return -EINVAL; + } + + errno =3D 0; + lresult =3D strtoul(nptr, &ep, base); + /* Windows returns 1 for negative out-of-range values. */ + if (errno =3D=3D ERANGE) { + *result =3D -1; + } else { + if (lresult > UINT_MAX) { + *result =3D UINT_MAX; + errno =3D ERANGE; + } else if (lresult < INT_MIN) { + *result =3D UINT_MAX; + errno =3D ERANGE; + } else { + *result =3D lresult; + } + } + return check_strtox_error(nptr, ep, endptr, errno); +} + /** * Convert string @nptr to a long integer, and store it in @result. * --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520886157347346.63381116281664; Mon, 12 Mar 2018 13:22:37 -0700 (PDT) Received: from localhost ([::1]:34450 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTxs-0002gZ-Il for importer@patchew.org; Mon, 12 Mar 2018 16:22:36 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39697) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp0-0004FI-BT for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:28 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTow-00074x-94 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:32798 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evTow-00074M-3W for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:22 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 276CA4068031; Mon, 12 Mar 2018 20:13:20 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 05C471102E25; Mon, 12 Mar 2018 20:13:18 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:12:59 +0000 Message-Id: <20180312201305.16972-4-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 12 Mar 2018 20:13:20 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 12 Mar 2018 20:13:20 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 3/9] sockets: pull code for testing IP availability out of specific test X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" The test-io-channel-socket.c file has some useful helper functions for checking if a specific IP protocol is available. Other tests need to perform similar kinds of checks to avoid running tests that will fail due to missing IP protocols. Reviewed-by: Eric Blake Reviewed-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- tests/Makefile.include | 2 +- tests/socket-helpers.c | 100 +++++++++++++++++++++++++++++++++++++= ++++ tests/socket-helpers.h | 42 +++++++++++++++++ tests/test-io-channel-socket.c | 72 +---------------------------- 4 files changed, 145 insertions(+), 71 deletions(-) create mode 100644 tests/socket-helpers.c create mode 100644 tests/socket-helpers.h diff --git a/tests/Makefile.include b/tests/Makefile.include index ef9b88c369..3d5b6174a8 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -715,7 +715,7 @@ tests/test-crypto-tlssession$(EXESUF): tests/test-crypt= o-tlssession.o \ tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y) tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y) tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \ - tests/io-channel-helpers.o $(test-io-obj-y) + tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y) tests/tpm-crb-test$(EXESUF): tests/tpm-crb-test.o tests/tpm-emu.o $(test-i= o-obj-y) tests/tpm-tis-test$(EXESUF): tests/tpm-tis-test.o tests/tpm-emu.o $(test-i= o-obj-y) tests/test-io-channel-file$(EXESUF): tests/test-io-channel-file.o \ diff --git a/tests/socket-helpers.c b/tests/socket-helpers.c new file mode 100644 index 0000000000..6f4bf07aa9 --- /dev/null +++ b/tests/socket-helpers.c @@ -0,0 +1,100 @@ +/* + * Helper functions for tests using sockets + * + * Copyright 2015-2018 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/sockets.h" +#include "socket-helpers.h" + +#ifndef AI_ADDRCONFIG +# define AI_ADDRCONFIG 0 +#endif +#ifndef EAI_ADDRFAMILY +# define EAI_ADDRFAMILY 0 +#endif + +int socket_can_bind(const char *hostname) +{ + int fd =3D -1; + struct addrinfo ai, *res =3D NULL; + int rc; + int ret =3D -1; + + memset(&ai, 0, sizeof(ai)); + ai.ai_flags =3D AI_CANONNAME | AI_ADDRCONFIG; + ai.ai_family =3D AF_UNSPEC; + ai.ai_socktype =3D SOCK_STREAM; + + /* lookup */ + rc =3D getaddrinfo(hostname, NULL, &ai, &res); + if (rc !=3D 0) { + if (rc =3D=3D EAI_ADDRFAMILY || + rc =3D=3D EAI_FAMILY) { + errno =3D EADDRNOTAVAIL; + } else { + errno =3D EINVAL; + } + goto cleanup; + } + + fd =3D qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol); + if (fd < 0) { + goto cleanup; + } + + if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) { + goto cleanup; + } + + ret =3D 0; + + cleanup: + if (fd !=3D -1) { + close(fd); + } + if (res) { + freeaddrinfo(res); + } + return ret; +} + + +int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6) +{ + *has_ipv4 =3D *has_ipv6 =3D false; + + if (socket_can_bind("127.0.0.1") < 0) { + if (errno !=3D EADDRNOTAVAIL) { + return -1; + } + } else { + *has_ipv4 =3D true; + } + + if (socket_can_bind("::1") < 0) { + if (errno !=3D EADDRNOTAVAIL) { + return -1; + } + } else { + *has_ipv6 =3D true; + } + + return 0; +} diff --git a/tests/socket-helpers.h b/tests/socket-helpers.h new file mode 100644 index 0000000000..efa96eddc2 --- /dev/null +++ b/tests/socket-helpers.h @@ -0,0 +1,42 @@ +/* + * Helper functions for tests using sockets + * + * Copyright 2015-2018 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or + * modify it under the terms of the GNU General Public License as + * published by the Free Software Foundation; either version 2 or + * (at your option) version 3 of the License. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this program; if not, see . + * + */ + +/* + * @hostname: a DNS name or numeric IP address + * + * Check whether it is possible to bind to ports + * on the DNS name or IP address @hostname. If an IP address + * is used, it must not be a wildcard address. + * + * Returns 0 on success, -1 on error with errno set + */ +int socket_can_bind(const char *hostname); + +/* + * @has_ipv4: set to true on return if IPv4 is available + * @has_ipv6: set to true on return if IPv6 is available + * + * Check whether IPv4 and/or IPv6 are available for use. + * On success, @has_ipv4 and @has_ipv6 will be set to + * indicate whether the respective protocols are available. + * + * Returns 0 on success, -1 on fatal error + */ +int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6); diff --git a/tests/test-io-channel-socket.c b/tests/test-io-channel-socket.c index b273fd3ba2..0597213f93 100644 --- a/tests/test-io-channel-socket.c +++ b/tests/test-io-channel-socket.c @@ -22,77 +22,9 @@ #include "io/channel-socket.h" #include "io/channel-util.h" #include "io-channel-helpers.h" +#include "socket-helpers.h" #include "qapi/error.h" =20 -#ifndef AI_ADDRCONFIG -# define AI_ADDRCONFIG 0 -#endif -#ifndef EAI_ADDRFAMILY -# define EAI_ADDRFAMILY 0 -#endif - -static int check_bind(const char *hostname, bool *has_proto) -{ - int fd =3D -1; - struct addrinfo ai, *res =3D NULL; - int rc; - int ret =3D -1; - - memset(&ai, 0, sizeof(ai)); - ai.ai_flags =3D AI_CANONNAME | AI_ADDRCONFIG; - ai.ai_family =3D AF_UNSPEC; - ai.ai_socktype =3D SOCK_STREAM; - - /* lookup */ - rc =3D getaddrinfo(hostname, NULL, &ai, &res); - if (rc !=3D 0) { - if (rc =3D=3D EAI_ADDRFAMILY || - rc =3D=3D EAI_FAMILY) { - *has_proto =3D false; - goto done; - } - goto cleanup; - } - - fd =3D qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (fd < 0) { - goto cleanup; - } - - if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) { - if (errno =3D=3D EADDRNOTAVAIL) { - *has_proto =3D false; - goto done; - } - goto cleanup; - } - - *has_proto =3D true; - done: - ret =3D 0; - - cleanup: - if (fd !=3D -1) { - close(fd); - } - if (res) { - freeaddrinfo(res); - } - return ret; -} - -static int check_protocol_support(bool *has_ipv4, bool *has_ipv6) -{ - if (check_bind("127.0.0.1", has_ipv4) < 0) { - return -1; - } - if (check_bind("::1", has_ipv6) < 0) { - return -1; - } - - return 0; -} - =20 static void test_io_channel_set_socket_bufs(QIOChannel *src, QIOChannel *dst) @@ -566,7 +498,7 @@ int main(int argc, char **argv) * each protocol to avoid breaking tests on machines * with either IPv4 or IPv6 disabled. */ - if (check_protocol_support(&has_ipv4, &has_ipv6) < 0) { + if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { return 1; } =20 --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520886045215189.59422039429876; Mon, 12 Mar 2018 13:20:45 -0700 (PDT) Received: from localhost ([::1]:34441 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTvx-0001BY-M6 for importer@patchew.org; Mon, 12 Mar 2018 16:20:37 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39706) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp0-0004FP-EF for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTow-00074g-7b for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:43326 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evTow-00074O-1m for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:22 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 7C62B20CC6; Mon, 12 Mar 2018 20:13:21 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 57CD51102E25; Mon, 12 Mar 2018 20:13:20 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:13:00 +0000 Message-Id: <20180312201305.16972-5-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Mon, 12 Mar 2018 20:13:21 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.1]); Mon, 12 Mar 2018 20:13:21 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 4/9] sockets: strengthen test suite IP protocol availability checks X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" Instead of just checking whether it is possible to bind() on a socket, also check that we can successfully connect() to the socket we bound to. This more closely replicates the level of functionality that tests will actually use. Reviewed-by: Eric Blake Reviewed-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- tests/socket-helpers.c | 67 +++++++++++++++++++++++++++++++++++++++++++---= ---- tests/socket-helpers.h | 4 +-- 2 files changed, 60 insertions(+), 11 deletions(-) diff --git a/tests/socket-helpers.c b/tests/socket-helpers.c index 6f4bf07aa9..8112763f5b 100644 --- a/tests/socket-helpers.c +++ b/tests/socket-helpers.c @@ -30,10 +30,15 @@ # define EAI_ADDRFAMILY 0 #endif =20 -int socket_can_bind(const char *hostname) +int socket_can_bind_connect(const char *hostname) { - int fd =3D -1; + int lfd =3D -1, cfd =3D -1, afd =3D -1; struct addrinfo ai, *res =3D NULL; + struct sockaddr_storage ss; + socklen_t sslen =3D sizeof(ss); + int soerr; + socklen_t soerrlen =3D sizeof(soerr); + bool check_soerr =3D false; int rc; int ret =3D -1; =20 @@ -54,20 +59,64 @@ int socket_can_bind(const char *hostname) goto cleanup; } =20 - fd =3D qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol); - if (fd < 0) { + lfd =3D qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol= ); + if (lfd < 0) { goto cleanup; } =20 - if (bind(fd, res->ai_addr, res->ai_addrlen) < 0) { + cfd =3D qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol= ); + if (cfd < 0) { goto cleanup; } =20 + if (bind(lfd, res->ai_addr, res->ai_addrlen) < 0) { + goto cleanup; + } + + if (listen(lfd, 1) < 0) { + goto cleanup; + } + + if (getsockname(lfd, (struct sockaddr *)&ss, &sslen) < 0) { + goto cleanup; + } + + qemu_set_nonblock(cfd); + if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) { + if (errno =3D=3D EINPROGRESS) { + check_soerr =3D true; + } else { + goto cleanup; + } + } + + sslen =3D sizeof(ss); + afd =3D accept(lfd, (struct sockaddr *)&ss, &sslen); + if (afd < 0) { + goto cleanup; + } + + if (check_soerr) { + if (qemu_getsockopt(cfd, SOL_SOCKET, SO_ERROR, &soerr, &soerrlen) = < 0) { + goto cleanup; + } + if (soerr) { + errno =3D soerr; + goto cleanup; + } + } + ret =3D 0; =20 cleanup: - if (fd !=3D -1) { - close(fd); + if (afd !=3D -1) { + close(afd); + } + if (cfd !=3D -1) { + close(cfd); + } + if (lfd !=3D -1) { + close(lfd); } if (res) { freeaddrinfo(res); @@ -80,7 +129,7 @@ int socket_check_protocol_support(bool *has_ipv4, bool *= has_ipv6) { *has_ipv4 =3D *has_ipv6 =3D false; =20 - if (socket_can_bind("127.0.0.1") < 0) { + if (socket_can_bind_connect("127.0.0.1") < 0) { if (errno !=3D EADDRNOTAVAIL) { return -1; } @@ -88,7 +137,7 @@ int socket_check_protocol_support(bool *has_ipv4, bool *= has_ipv6) *has_ipv4 =3D true; } =20 - if (socket_can_bind("::1") < 0) { + if (socket_can_bind_connect("::1") < 0) { if (errno !=3D EADDRNOTAVAIL) { return -1; } diff --git a/tests/socket-helpers.h b/tests/socket-helpers.h index efa96eddc2..1c07d6d656 100644 --- a/tests/socket-helpers.h +++ b/tests/socket-helpers.h @@ -21,13 +21,13 @@ /* * @hostname: a DNS name or numeric IP address * - * Check whether it is possible to bind to ports + * Check whether it is possible to bind & connect to ports * on the DNS name or IP address @hostname. If an IP address * is used, it must not be a wildcard address. * * Returns 0 on success, -1 on error with errno set */ -int socket_can_bind(const char *hostname); +int socket_can_bind_connect(const char *hostname); =20 /* * @has_ipv4: set to true on return if IPv4 is available --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 152088574077965.7608554896143; Mon, 12 Mar 2018 13:15:40 -0700 (PDT) Received: from localhost ([::1]:34409 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTr5-0005ZL-IK for importer@patchew.org; Mon, 12 Mar 2018 16:15:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39705) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp0-0004FO-E4 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTox-00075W-D4 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35846 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evTox-00075K-7O for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:23 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id D4DFE8182D1E; Mon, 12 Mar 2018 20:13:22 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id AD88D1102E24; Mon, 12 Mar 2018 20:13:21 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:13:01 +0000 Message-Id: <20180312201305.16972-6-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 12 Mar 2018 20:13:22 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 12 Mar 2018 20:13:22 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 5/9] sockets: move fd_is_socket() into common sockets code X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" The fd_is_socket() helper method is useful in a few places, so put it in the common sockets code. Make the code more compact while moving it. Reviewed-by: Eric Blake Reviewed-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- include/qemu/sockets.h | 1 + io/channel-util.c | 13 -------- tests/.gitignore | 1 + tests/Makefile.include | 3 ++ tests/test-util-sockets.c | 77 +++++++++++++++++++++++++++++++++++++++++++= ++++ util/qemu-sockets.c | 8 +++++ 6 files changed, 90 insertions(+), 13 deletions(-) create mode 100644 tests/test-util-sockets.c diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h index e88d4c37ab..8140fea685 100644 --- a/include/qemu/sockets.h +++ b/include/qemu/sockets.h @@ -12,6 +12,7 @@ int inet_aton(const char *cp, struct in_addr *ia); #include "qapi/qapi-types-sockets.h" =20 /* misc helpers */ +bool fd_is_socket(int fd); int qemu_socket(int domain, int type, int protocol); int qemu_accept(int s, struct sockaddr *addr, socklen_t *addrlen); int socket_set_cork(int fd, int v); diff --git a/io/channel-util.c b/io/channel-util.c index 0fb4bd0837..423d79845a 100644 --- a/io/channel-util.c +++ b/io/channel-util.c @@ -24,19 +24,6 @@ #include "io/channel-socket.h" =20 =20 -static bool fd_is_socket(int fd) -{ - int optval; - socklen_t optlen; - optlen =3D sizeof(optval); - return qemu_getsockopt(fd, - SOL_SOCKET, - SO_TYPE, - (char *)&optval, - &optlen) =3D=3D 0; -} - - QIOChannel *qio_channel_new_fd(int fd, Error **errp) { diff --git a/tests/.gitignore b/tests/.gitignore index 18e58b2183..fb62d2299b 100644 --- a/tests/.gitignore +++ b/tests/.gitignore @@ -86,6 +86,7 @@ test-thread-pool test-throttle test-timed-average test-uuid +test-util-sockets test-visitor-serialization test-vmstate test-write-threshold diff --git a/tests/Makefile.include b/tests/Makefile.include index 3d5b6174a8..42fd426cd0 100644 --- a/tests/Makefile.include +++ b/tests/Makefile.include @@ -146,6 +146,7 @@ ifneq (,$(findstring qemu-ga,$(TOOLS))) check-unit-$(CONFIG_LINUX) +=3D tests/test-qga$(EXESUF) endif check-unit-y +=3D tests/test-timed-average$(EXESUF) +check-unit-y +=3D tests/test-util-sockets$(EXESUF) check-unit-y +=3D tests/test-io-task$(EXESUF) check-unit-y +=3D tests/test-io-channel-socket$(EXESUF) check-unit-y +=3D tests/test-io-channel-file$(EXESUF) @@ -713,6 +714,8 @@ tests/test-crypto-tlscredsx509$(EXESUF): tests/test-cry= pto-tlscredsx509.o \ tests/test-crypto-tlssession.o-cflags :=3D $(TASN1_CFLAGS) tests/test-crypto-tlssession$(EXESUF): tests/test-crypto-tlssession.o \ tests/crypto-tls-x509-helpers.o tests/pkix_asn1_tab.o $(test-crypto-obj-y) +tests/test-util-sockets$(EXESUF): tests/test-util-sockets.o \ + tests/socket-helpers.o $(test-util-obj-y) tests/test-io-task$(EXESUF): tests/test-io-task.o $(test-io-obj-y) tests/test-io-channel-socket$(EXESUF): tests/test-io-channel-socket.o \ tests/io-channel-helpers.o tests/socket-helpers.o $(test-io-obj-y) diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c new file mode 100644 index 0000000000..65190e0530 --- /dev/null +++ b/tests/test-util-sockets.c @@ -0,0 +1,77 @@ +/* + * Tests for util/qemu-sockets.c + * + * Copyright 2018 Red Hat, Inc. + * + * This program is free software; you can redistribute it and/or modify + * it under the terms of the GNU General Public License as published by + * the Free Software Foundation; either version 2 of the License, or + * (at your option) any later version. + * + * This program 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 General Public License for more details. + * + * You should have received a copy of the GNU General Public License + * along with this library; if not, see . + * + */ + +#include "qemu/osdep.h" +#include "qemu-common.h" +#include "qemu/sockets.h" +#include "qapi/error.h" +#include "socket-helpers.h" + +static void test_fd_is_socket_bad(void) +{ + char *tmp =3D g_strdup("qemu-test-util-sockets-XXXXXX"); + int fd =3D mkstemp(tmp); + if (fd !=3D 0) { + unlink(tmp); + } + g_free(tmp); + + g_assert(fd >=3D 0); + + g_assert(!fd_is_socket(fd)); + close(fd); +} + +static void test_fd_is_socket_good(void) +{ + int fd =3D qemu_socket(PF_INET, SOCK_STREAM, 0); + + g_assert(fd >=3D 0); + + g_assert(fd_is_socket(fd)); + close(fd); +} + +int main(int argc, char **argv) +{ + bool has_ipv4, has_ipv6; + + socket_init(); + + g_test_init(&argc, &argv, NULL); + + /* We're creating actual IPv4/6 sockets, so we should + * check if the host running tests actually supports + * each protocol to avoid breaking tests on machines + * with either IPv4 or IPv6 disabled. + */ + if (socket_check_protocol_support(&has_ipv4, &has_ipv6) < 0) { + return 1; + } + + if (has_ipv4) { + g_test_add_func("/util/socket/is-socket/bad", + test_fd_is_socket_bad); + g_test_add_func("/util/socket/is-socket/good", + test_fd_is_socket_good); + } + + return g_test_run(); +} diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 7f13e8a338..fa79471647 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -91,6 +91,14 @@ NetworkAddressFamily inet_netfamily(int family) return NETWORK_ADDRESS_FAMILY_UNKNOWN; } =20 +bool fd_is_socket(int fd) +{ + int optval; + socklen_t optlen =3D sizeof(optval); + return !qemu_getsockopt(fd, SOL_SOCKET, SO_TYPE, &optval, &optlen); +} + + /* * Matrix we're trying to apply * --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 15208859003221020.1220062595155; Mon, 12 Mar 2018 13:18:20 -0700 (PDT) Received: from localhost ([::1]:34428 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTtj-0007u1-Bw for importer@patchew.org; Mon, 12 Mar 2018 16:18:19 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39698) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp0-0004FJ-Bl for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:27 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evToy-00076A-MD for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:26 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:35858 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evToy-00075x-H9 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:24 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 2CE49814F0D2; Mon, 12 Mar 2018 20:13:24 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 0C0851102E24; Mon, 12 Mar 2018 20:13:22 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:13:02 +0000 Message-Id: <20180312201305.16972-7-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 12 Mar 2018 20:13:24 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.8]); Mon, 12 Mar 2018 20:13:24 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 6/9] sockets: check that the named file descriptor is a socket X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" The SocketAddress struct has an "fd" type, which references the name of a file descriptor passed over the monitor using the "getfd" command. We currently blindly assume the FD is a socket, which can lead to hard to diagnose errors later. This adds an explicit check that the FD is actually a socket to improve the error diagnosis. Reviewed-by: Eric Blake Reviewed-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- tests/test-util-sockets.c | 89 +++++++++++++++++++++++++++++++++++++++++++= ++++ util/qemu-sockets.c | 18 ++++++++-- 2 files changed, 105 insertions(+), 2 deletions(-) diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index 65190e0530..06eb0e4a28 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -23,6 +23,7 @@ #include "qemu/sockets.h" #include "qapi/error.h" #include "socket-helpers.h" +#include "monitor/monitor.h" =20 static void test_fd_is_socket_bad(void) { @@ -49,6 +50,90 @@ static void test_fd_is_socket_good(void) close(fd); } =20 +static int mon_fd =3D -1; +static const char *mon_fdname; + +int monitor_get_fd(Monitor *mon, const char *fdname, Error **errp) +{ + g_assert(cur_mon); + g_assert(mon =3D=3D cur_mon); + if (mon_fd =3D=3D -1 || !g_str_equal(mon_fdname, fdname)) { + error_setg(errp, "No fd named %s", fdname); + return -1; + } + return dup(mon_fd); +} + +/* Syms in libqemustub.a are discarded at .o file granularity. + * To replace monitor_get_fd() we must ensure everything in + * stubs/monitor.c is defined, to make sure monitor.o is discarded + * otherwise we get duplicate syms at link time. + */ +Monitor *cur_mon; +void monitor_init(Chardev *chr, int flags) {} + + +static void test_socket_fd_pass_good(void) +{ + SocketAddress addr; + int fd; + + cur_mon =3D g_malloc(1); /* Fake a monitor */ + mon_fdname =3D "myfd"; + mon_fd =3D qemu_socket(AF_INET, SOCK_STREAM, 0); + g_assert_cmpint(mon_fd, >, STDERR_FILENO); + + addr.type =3D SOCKET_ADDRESS_TYPE_FD; + addr.u.fd.str =3D g_strdup(mon_fdname); + + fd =3D socket_connect(&addr, &error_abort); + g_assert_cmpint(fd, !=3D, -1); + g_assert_cmpint(fd, !=3D, mon_fd); + close(fd); + + fd =3D socket_listen(&addr, &error_abort); + g_assert_cmpint(fd, !=3D, -1); + g_assert_cmpint(fd, !=3D, mon_fd); + close(fd); + + g_free(addr.u.fd.str); + mon_fdname =3D NULL; + close(mon_fd); + mon_fd =3D -1; + g_free(cur_mon); + cur_mon =3D NULL; +} + +static void test_socket_fd_pass_bad(void) +{ + SocketAddress addr; + Error *err =3D NULL; + int fd; + + cur_mon =3D g_malloc(1); /* Fake a monitor */ + mon_fdname =3D "myfd"; + mon_fd =3D dup(STDOUT_FILENO); + g_assert_cmpint(mon_fd, >, STDERR_FILENO); + + addr.type =3D SOCKET_ADDRESS_TYPE_FD; + addr.u.fd.str =3D g_strdup(mon_fdname); + + fd =3D socket_connect(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + fd =3D socket_listen(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + g_free(addr.u.fd.str); + mon_fdname =3D NULL; + close(mon_fd); + mon_fd =3D -1; + g_free(cur_mon); + cur_mon =3D NULL; +} + int main(int argc, char **argv) { bool has_ipv4, has_ipv6; @@ -71,6 +156,10 @@ int main(int argc, char **argv) test_fd_is_socket_bad); g_test_add_func("/util/socket/is-socket/good", test_fd_is_socket_good); + g_test_add_func("/socket/fd-pass/good", + test_socket_fd_pass_good); + g_test_add_func("/socket/fd-pass/bad", + test_socket_fd_pass_bad); } =20 return g_test_run(); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index fa79471647..6dc4613855 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1042,6 +1042,20 @@ fail: return NULL; } =20 +static int socket_get_fd(const char *fdstr, Error **errp) +{ + int fd =3D monitor_get_fd(cur_mon, fdstr, errp); + if (fd < 0) { + return -1; + } + if (!fd_is_socket(fd)) { + error_setg(errp, "File descriptor '%s' is not a socket", fdstr); + close(fd); + return -1; + } + return fd; +} + int socket_connect(SocketAddress *addr, Error **errp) { int fd; @@ -1056,7 +1070,7 @@ int socket_connect(SocketAddress *addr, Error **errp) break; =20 case SOCKET_ADDRESS_TYPE_FD: - fd =3D monitor_get_fd(cur_mon, addr->u.fd.str, errp); + fd =3D socket_get_fd(addr->u.fd.str, errp); break; =20 case SOCKET_ADDRESS_TYPE_VSOCK: @@ -1083,7 +1097,7 @@ int socket_listen(SocketAddress *addr, Error **errp) break; =20 case SOCKET_ADDRESS_TYPE_FD: - fd =3D monitor_get_fd(cur_mon, addr->u.fd.str, errp); + fd =3D socket_get_fd(addr->u.fd.str, errp); break; =20 case SOCKET_ADDRESS_TYPE_VSOCK: --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (208.118.235.17 [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520885740802350.2429676458396; Mon, 12 Mar 2018 13:15:40 -0700 (PDT) Received: from localhost ([::1]:34410 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTr5-0005Zo-BN for importer@patchew.org; Mon, 12 Mar 2018 16:15:35 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39737) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp1-0004Fq-Nd for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTp0-00076u-0q for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:27 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:51452 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evToz-00076f-Qi for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:25 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 80B5E406E8B9; Mon, 12 Mar 2018 20:13:25 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 5F07D1102E24; Mon, 12 Mar 2018 20:13:24 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:13:03 +0000 Message-Id: <20180312201305.16972-8-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 12 Mar 2018 20:13:25 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.7]); Mon, 12 Mar 2018 20:13:25 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 7/9] sockets: allow SocketAddress 'fd' to reference numeric file descriptors X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" The SocketAddress 'fd' kind accepts the name of a file descriptor passed to the monitor with the 'getfd' command. This makes it impossible to use the 'fd' kind in cases where a monitor is not available. This can apply in handling command line argv at startup, or simply if internal code wants to use SocketAddress and pass a numeric FD it has acquired from elsewhere. Fortunately the 'getfd' command mandated that the FD names must not start with a leading digit. We can thus safely extend semantics of the SocketAddress 'fd' kind, to allow a purely numeric name to reference an file descriptor that QEMU already has open. There will be restrictions on when each kind can be used. In codepaths where we are handling a monitor command (ie cur_mon !=3D NULL), we will only support use of named file descriptors as before. Use of FD numbers is still not permitted for monitor commands. In codepaths where we are not handling a monitor command (ie cur_mon =3D=3D NULL), we will not support named file descriptors. Instead we can reference FD numers explicitly. This allows the app spawning QEMU to intentionally "leak" a pre-opened socket to QEMU and reference that in a SocketAddress definition, or for code inside QEMU to pass pre-opened FDs around. Reviewed-by: Eric Blake Reviewed-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- qapi/sockets.json | 7 +++ tests/test-util-sockets.c | 112 ++++++++++++++++++++++++++++++++++++++++++= +--- util/qemu-sockets.c | 16 +++++-- 3 files changed, 126 insertions(+), 9 deletions(-) diff --git a/qapi/sockets.json b/qapi/sockets.json index ac022c6ad0..fc81d8d5e8 100644 --- a/qapi/sockets.json +++ b/qapi/sockets.json @@ -123,6 +123,13 @@ # # @unix: Unix domain socket # +# @vsock: VMCI address +# +# @fd: decimal is for file descriptor number, otherwise a file descriptor = name. +# Named file descriptors are permitted in monitor commands, in combin= ation +# with the 'getfd' command. Decimal file descriptors are permitted at +# startup or other contexts where no monitor context is active. +# # Since: 2.9 ## { 'enum': 'SocketAddressType', diff --git a/tests/test-util-sockets.c b/tests/test-util-sockets.c index 06eb0e4a28..acadd85e8f 100644 --- a/tests/test-util-sockets.c +++ b/tests/test-util-sockets.c @@ -73,7 +73,7 @@ Monitor *cur_mon; void monitor_init(Chardev *chr, int flags) {} =20 =20 -static void test_socket_fd_pass_good(void) +static void test_socket_fd_pass_name_good(void) { SocketAddress addr; int fd; @@ -104,7 +104,7 @@ static void test_socket_fd_pass_good(void) cur_mon =3D NULL; } =20 -static void test_socket_fd_pass_bad(void) +static void test_socket_fd_pass_name_bad(void) { SocketAddress addr; Error *err =3D NULL; @@ -134,6 +134,98 @@ static void test_socket_fd_pass_bad(void) cur_mon =3D NULL; } =20 +static void test_socket_fd_pass_name_nomon(void) +{ + SocketAddress addr; + Error *err =3D NULL; + int fd; + + g_assert(cur_mon =3D=3D NULL); + + addr.type =3D SOCKET_ADDRESS_TYPE_FD; + addr.u.fd.str =3D g_strdup("myfd"); + + fd =3D socket_connect(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + fd =3D socket_listen(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + g_free(addr.u.fd.str); +} + + +static void test_socket_fd_pass_num_good(void) +{ + SocketAddress addr; + int fd, sfd; + + g_assert(cur_mon =3D=3D NULL); + sfd =3D qemu_socket(AF_INET, SOCK_STREAM, 0); + g_assert_cmpint(sfd, >, STDERR_FILENO); + + addr.type =3D SOCKET_ADDRESS_TYPE_FD; + addr.u.fd.str =3D g_strdup_printf("%d", sfd); + + fd =3D socket_connect(&addr, &error_abort); + g_assert_cmpint(fd, =3D=3D, sfd); + + fd =3D socket_listen(&addr, &error_abort); + g_assert_cmpint(fd, =3D=3D, sfd); + + g_free(addr.u.fd.str); + close(sfd); +} + +static void test_socket_fd_pass_num_bad(void) +{ + SocketAddress addr; + Error *err =3D NULL; + int fd, sfd; + + g_assert(cur_mon =3D=3D NULL); + sfd =3D dup(STDOUT_FILENO); + + addr.type =3D SOCKET_ADDRESS_TYPE_FD; + addr.u.fd.str =3D g_strdup_printf("%d", sfd); + + fd =3D socket_connect(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + fd =3D socket_listen(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + g_free(addr.u.fd.str); + close(sfd); +} + +static void test_socket_fd_pass_num_nocli(void) +{ + SocketAddress addr; + Error *err =3D NULL; + int fd; + + cur_mon =3D g_malloc(1); /* Fake a monitor */ + + addr.type =3D SOCKET_ADDRESS_TYPE_FD; + addr.u.fd.str =3D g_strdup_printf("%d", STDOUT_FILENO); + + fd =3D socket_connect(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + fd =3D socket_listen(&addr, &err); + g_assert_cmpint(fd, =3D=3D, -1); + error_free_or_abort(&err); + + g_free(addr.u.fd.str); +} + + int main(int argc, char **argv) { bool has_ipv4, has_ipv6; @@ -156,10 +248,18 @@ int main(int argc, char **argv) test_fd_is_socket_bad); g_test_add_func("/util/socket/is-socket/good", test_fd_is_socket_good); - g_test_add_func("/socket/fd-pass/good", - test_socket_fd_pass_good); - g_test_add_func("/socket/fd-pass/bad", - test_socket_fd_pass_bad); + g_test_add_func("/socket/fd-pass/name/good", + test_socket_fd_pass_name_good); + g_test_add_func("/socket/fd-pass/name/bad", + test_socket_fd_pass_name_bad); + g_test_add_func("/socket/fd-pass/name/nomon", + test_socket_fd_pass_name_nomon); + g_test_add_func("/socket/fd-pass/num/good", + test_socket_fd_pass_num_good); + g_test_add_func("/socket/fd-pass/num/bad", + test_socket_fd_pass_num_bad); + g_test_add_func("/socket/fd-pass/num/nocli", + test_socket_fd_pass_num_nocli); } =20 return g_test_run(); diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c index 6dc4613855..8bd8bb64eb 100644 --- a/util/qemu-sockets.c +++ b/util/qemu-sockets.c @@ -1044,9 +1044,19 @@ fail: =20 static int socket_get_fd(const char *fdstr, Error **errp) { - int fd =3D monitor_get_fd(cur_mon, fdstr, errp); - if (fd < 0) { - return -1; + int fd; + if (cur_mon) { + fd =3D monitor_get_fd(cur_mon, fdstr, errp); + if (fd < 0) { + return -1; + } + } else { + if (qemu_strtoi(fdstr, NULL, 10, &fd) < 0) { + error_setg_errno(errp, errno, + "Unable to parse FD number %s", + fdstr); + return -1; + } } if (!fd_is_socket(fd)) { error_setg(errp, "File descriptor '%s' is not a socket", fdstr); --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520885902698307.83758893937306; Mon, 12 Mar 2018 13:18:22 -0700 (PDT) Received: from localhost ([::1]:34429 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTtl-0007vs-Qy for importer@patchew.org; Mon, 12 Mar 2018 16:18:21 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39751) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp2-0004GO-J6 for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:29 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTp1-000788-DL for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:28 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:41358 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evTp1-00077s-8u for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:27 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id DE40E8E7B4; Mon, 12 Mar 2018 20:13:26 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id B249E1102E24; Mon, 12 Mar 2018 20:13:25 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:13:04 +0000 Message-Id: <20180312201305.16972-9-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> MIME-Version: 1.0 X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 12 Mar 2018 20:13:26 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.2]); Mon, 12 Mar 2018 20:13:26 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' Content-Transfer-Encoding: quoted-printable X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 8/9] char: refactor parsing of socket address information X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" To prepare for handling more address types, refactor the parsing of socket address information to make it more robust and extensible. Reviewed-by: Eric Blake Reviewed-by: Marc-Andr=C3=A9 Lureau Signed-off-by: Daniel P. Berrange --- chardev/char-socket.c | 22 ++++++++++++++-------- 1 file changed, 14 insertions(+), 8 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index 1a371b91ac..a916ef4012 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1012,21 +1012,25 @@ static void qemu_chr_parse_socket(QemuOpts *opts, C= hardevBackend *backend, SocketAddressLegacy *addr; ChardevSocket *sock; =20 + if ((!!path + !!host) !=3D 1) { + error_setg(errp, + "Exactly one of 'path' or 'host' required"); + return; + } + backend->type =3D CHARDEV_BACKEND_KIND_SOCKET; - if (!path) { - if (!host) { - error_setg(errp, "chardev: socket: no host given"); + if (path) { + if (tls_creds) { + error_setg(errp, "TLS can only be used over TCP socket"); return; } + } else if (host) { if (!port) { error_setg(errp, "chardev: socket: no port given"); return; } } else { - if (tls_creds) { - error_setg(errp, "TLS can only be used over TCP socket"); - return; - } + g_assert_not_reached(); } =20 sock =3D backend->u.socket.data =3D g_new0(ChardevSocket, 1); @@ -1052,7 +1056,7 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Cha= rdevBackend *backend, addr->type =3D SOCKET_ADDRESS_LEGACY_KIND_UNIX; q_unix =3D addr->u.q_unix.data =3D g_new0(UnixSocketAddress, 1); q_unix->path =3D g_strdup(path); - } else { + } else if (host) { addr->type =3D SOCKET_ADDRESS_LEGACY_KIND_INET; addr->u.inet.data =3D g_new(InetSocketAddress, 1); *addr->u.inet.data =3D (InetSocketAddress) { @@ -1065,6 +1069,8 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Cha= rdevBackend *backend, .has_ipv6 =3D qemu_opt_get(opts, "ipv6"), .ipv6 =3D qemu_opt_get_bool(opts, "ipv6", 0), }; + } else { + g_assert_not_reached(); } sock->addr =3D addr; } --=20 2.14.3 From nobody Thu Mar 28 09:30:10 2024 Delivered-To: importer@patchew.org Received-SPF: pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) client-ip=208.118.235.17; envelope-from=qemu-devel-bounces+importer=patchew.org@nongnu.org; helo=lists.gnu.org; Authentication-Results: mx.zohomail.com; spf=pass (zoho.com: domain of gnu.org designates 208.118.235.17 as permitted sender) smtp.mailfrom=qemu-devel-bounces+importer=patchew.org@nongnu.org; dmarc=fail(p=none dis=none) header.from=redhat.com Return-Path: Received: from lists.gnu.org (lists.gnu.org [208.118.235.17]) by mx.zohomail.com with SMTPS id 1520886040680435.47010238210123; Mon, 12 Mar 2018 13:20:40 -0700 (PDT) Received: from localhost ([::1]:34444 helo=lists.gnu.org) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTvz-0001EG-S4 for importer@patchew.org; Mon, 12 Mar 2018 16:20:39 -0400 Received: from eggs.gnu.org ([2001:4830:134:3::10]:39772) by lists.gnu.org with esmtp (Exim 4.71) (envelope-from ) id 1evTp4-0004I5-5S for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:31 -0400 Received: from Debian-exim by eggs.gnu.org with spam-scanned (Exim 4.71) (envelope-from ) id 1evTp2-00078x-Ni for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:30 -0400 Received: from mx3-rdu2.redhat.com ([66.187.233.73]:32806 helo=mx1.redhat.com) by eggs.gnu.org with esmtps (TLS1.0:DHE_RSA_AES_256_CBC_SHA1:32) (Exim 4.71) (envelope-from ) id 1evTp2-00078g-IE for qemu-devel@nongnu.org; Mon, 12 Mar 2018 16:13:28 -0400 Received: from smtp.corp.redhat.com (int-mx03.intmail.prod.int.rdu2.redhat.com [10.11.54.3]) (using TLSv1.2 with cipher AECDH-AES256-SHA (256/256 bits)) (No client certificate requested) by mx1.redhat.com (Postfix) with ESMTPS id 4114B4068031; Mon, 12 Mar 2018 20:13:28 +0000 (UTC) Received: from t460.redhat.com (unknown [10.33.36.24]) by smtp.corp.redhat.com (Postfix) with ESMTP id 1B2891102E24; Mon, 12 Mar 2018 20:13:27 +0000 (UTC) From: =?UTF-8?q?Daniel=20P=2E=20Berrang=C3=A9?= To: qemu-devel@nongnu.org Date: Mon, 12 Mar 2018 20:13:05 +0000 Message-Id: <20180312201305.16972-10-berrange@redhat.com> In-Reply-To: <20180312201305.16972-1-berrange@redhat.com> References: <20180312201305.16972-1-berrange@redhat.com> X-Scanned-By: MIMEDefang 2.78 on 10.11.54.3 X-Greylist: Sender IP whitelisted, not delayed by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 12 Mar 2018 20:13:28 +0000 (UTC) X-Greylist: inspected by milter-greylist-4.5.16 (mx1.redhat.com [10.11.55.5]); Mon, 12 Mar 2018 20:13:28 +0000 (UTC) for IP:'10.11.54.3' DOMAIN:'int-mx03.intmail.prod.int.rdu2.redhat.com' HELO:'smtp.corp.redhat.com' FROM:'berrange@redhat.com' RCPT:'' X-detected-operating-system: by eggs.gnu.org: GNU/Linux 2.2.x-3.x [generic] [fuzzy] X-Received-From: 66.187.233.73 Subject: [Qemu-devel] [PULL 9/9] char: allow passing pre-opened socket file descriptor at startup X-BeenThere: qemu-devel@nongnu.org X-Mailman-Version: 2.1.21 Precedence: list List-Id: List-Unsubscribe: , List-Archive: List-Post: List-Help: List-Subscribe: , Cc: Peter Maydell , Markus Armbruster , Gerd Hoffmann , =?UTF-8?q?Marc-Andr=C3=A9=20Lureau?= , Paolo Bonzini Errors-To: qemu-devel-bounces+importer=patchew.org@nongnu.org Sender: "Qemu-devel" X-ZohoMail: RSF_0 Z_629925259 SPT_0 Content-Transfer-Encoding: quoted-printable MIME-Version: 1.0 Content-Type: text/plain; charset="utf-8" From: "Daniel P. Berrange" When starting QEMU management apps will usually setup a monitor socket, and then open it immediately after startup. If not using QEMU's own -daemonize arg, this process can be troublesome to handle correctly. The mgmt app will need to repeatedly call connect() until it succeeds, because it does not know when QEMU has created the listener socket. If can't retry connect() forever though, because an error might have caused QEMU to exit before it even creates the monitor. The obvious way to fix this kind of problem is to just pass in a pre-opened socket file descriptor for the QEMU monitor to listen on. The management app can now immediately call connect() just once. If connect() fails it knows that QEMU has exited with an error. The SocketAddress(Legacy) structs allow for FD passing via the monitor, and now via inherited file descriptors from the process that spawned QEMU. The final missing piece is adding a 'fd' parameter in the socket chardev options. This allows both HMP usage, pass any FD number with SCM_RIGHTS, then running HMP commands: getfd myfd chardev-add socket,fd=3Dmyfd Note that numeric FDs cannot be referenced directly in HMP, only named FDs. And also CLI usage, by leak FD 3 from parent by clearing O_CLOEXEC, then spawning QEMU with -chardev socket,fd=3D3,id=3Dmon -mon chardev=3Dmon,mode=3Dcontrol Note that named FDs cannot be referenced in CLI args, only numeric FDs. We do not wire this up in the legacy chardev syntax, so you cannot use FD passing with '-qmp', you must use the modern '-mon' + '-chardev' pair. When passing pre-opened FDs there is a restriction on use of TLS encryption. It can be used on a server socket chardev, but cannot be used for a client socket chardev. This is because when validating a server's certificate, the client needs to have a hostname available to match against the certificate identity. An illustrative example of usage is: #!/usr/bin/perl use IO::Socket::UNIX; use Fcntl; unlink "/tmp/qmp"; my $srv =3D IO::Socket::UNIX->new( Type =3D> SOCK_STREAM(), Local =3D> "/tmp/qmp", Listen =3D> 1, ); my $flags =3D fcntl $srv, F_GETFD, 0; fcntl $srv, F_SETFD, $flags & ~FD_CLOEXEC; my $fd =3D $srv->fileno(); exec "qemu-system-x86_64", \ "-chardev", "socket,fd=3D$fd,server,nowait,id=3Dmon", \ "-mon", "chardev=3Dmon,mode=3Dcontrol"; Reviewed-by: Eric Blake Signed-off-by: Daniel P. Berrange --- chardev/char-socket.c | 15 +++++++++++++-- chardev/char.c | 3 +++ tests/test-char.c | 47 ++++++++++++++++++++++++++++++++++++++++++++--- 3 files changed, 60 insertions(+), 5 deletions(-) diff --git a/chardev/char-socket.c b/chardev/char-socket.c index a916ef4012..0c8d6d430a 100644 --- a/chardev/char-socket.c +++ b/chardev/char-socket.c @@ -1008,13 +1008,14 @@ static void qemu_chr_parse_socket(QemuOpts *opts, C= hardevBackend *backend, const char *path =3D qemu_opt_get(opts, "path"); const char *host =3D qemu_opt_get(opts, "host"); const char *port =3D qemu_opt_get(opts, "port"); + const char *fd =3D qemu_opt_get(opts, "fd"); const char *tls_creds =3D qemu_opt_get(opts, "tls-creds"); SocketAddressLegacy *addr; ChardevSocket *sock; =20 - if ((!!path + !!host) !=3D 1) { + if ((!!path + !!fd + !!host) !=3D 1) { error_setg(errp, - "Exactly one of 'path' or 'host' required"); + "Exactly one of 'path', 'fd' or 'host' required"); return; } =20 @@ -1029,6 +1030,12 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Ch= ardevBackend *backend, error_setg(errp, "chardev: socket: no port given"); return; } + } else if (fd) { + /* We don't know what host to validate against when in client mode= */ + if (tls_creds && !is_listen) { + error_setg(errp, "TLS can not be used with pre-opened client F= D"); + return; + } } else { g_assert_not_reached(); } @@ -1069,6 +1076,10 @@ static void qemu_chr_parse_socket(QemuOpts *opts, Ch= ardevBackend *backend, .has_ipv6 =3D qemu_opt_get(opts, "ipv6"), .ipv6 =3D qemu_opt_get_bool(opts, "ipv6", 0), }; + } else if (fd) { + addr->type =3D SOCKET_ADDRESS_LEGACY_KIND_FD; + addr->u.fd.data =3D g_new(String, 1); + addr->u.fd.data->str =3D g_strdup(fd); } else { g_assert_not_reached(); } diff --git a/chardev/char.c b/chardev/char.c index 5d7b079ef0..f7e0d37f24 100644 --- a/chardev/char.c +++ b/chardev/char.c @@ -807,6 +807,9 @@ QemuOptsList qemu_chardev_opts =3D { },{ .name =3D "port", .type =3D QEMU_OPT_STRING, + },{ + .name =3D "fd", + .type =3D QEMU_OPT_STRING, },{ .name =3D "localaddr", .type =3D QEMU_OPT_STRING, diff --git a/tests/test-char.c b/tests/test-char.c index b3a77af085..dffb354202 100644 --- a/tests/test-char.c +++ b/tests/test-char.c @@ -302,9 +302,8 @@ static int socket_can_read_hello(void *opaque) return 10; } =20 -static void char_socket_test(void) +static void char_socket_test_common(Chardev *chr) { - Chardev *chr =3D qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait= "); Chardev *chr_client; QObject *addr; QDict *qdict; @@ -359,6 +358,47 @@ static void char_socket_test(void) object_unparent(OBJECT(chr)); } =20 + +static void char_socket_basic_test(void) +{ + Chardev *chr =3D qemu_chr_new("server", "tcp:127.0.0.1:0,server,nowait= "); + + char_socket_test_common(chr); +} + + +static void char_socket_fdpass_test(void) +{ + Chardev *chr; + char *optstr; + QemuOpts *opts; + int fd; + SocketAddress *addr =3D g_new0(SocketAddress, 1); + + addr->type =3D SOCKET_ADDRESS_TYPE_INET; + addr->u.inet.host =3D g_strdup("127.0.0.1"); + addr->u.inet.port =3D g_strdup("0"); + + fd =3D socket_listen(addr, &error_abort); + g_assert(fd >=3D 0); + + qapi_free_SocketAddress(addr); + + optstr =3D g_strdup_printf("socket,id=3Dcdev,fd=3D%d,server,nowait", f= d); + + opts =3D qemu_opts_parse_noisily(qemu_find_opts("chardev"), + optstr, true); + g_free(optstr); + g_assert_nonnull(opts); + + chr =3D qemu_chr_new_from_opts(opts, &error_abort); + + qemu_opts_del(opts); + + char_socket_test_common(chr); +} + + #ifndef _WIN32 static void char_pipe_test(void) { @@ -775,7 +815,8 @@ int main(int argc, char **argv) #ifndef _WIN32 g_test_add_func("/char/file-fifo", char_file_fifo_test); #endif - g_test_add_func("/char/socket", char_socket_test); + g_test_add_func("/char/socket/basic", char_socket_basic_test); + g_test_add_func("/char/socket/fdpass", char_socket_fdpass_test); g_test_add_func("/char/udp", char_udp_test); #ifdef HAVE_CHARDEV_SERIAL g_test_add_func("/char/serial", char_serial_test); --=20 2.14.3