summaryrefslogtreecommitdiffstats
path: root/tests/unit/socket-helpers.c
diff options
context:
space:
mode:
authorPeter Maydell2021-03-14 16:13:53 +0100
committerPeter Maydell2021-03-14 16:13:53 +0100
commit757acb9a8295e8be4a37b2cfc1cd947e357fd29c (patch)
tree881fdcb812a8b8d067d5cb59832b3bb31ce9bcf9 /tests/unit/socket-helpers.c
parentMerge remote-tracking branch 'remotes/pmaydell/tags/pull-target-arm-20210314'... (diff)
parentREADME: Add Documentation blurb (diff)
downloadqemu-757acb9a8295e8be4a37b2cfc1cd947e357fd29c.tar.gz
qemu-757acb9a8295e8be4a37b2cfc1cd947e357fd29c.tar.xz
qemu-757acb9a8295e8be4a37b2cfc1cd947e357fd29c.zip
Merge remote-tracking branch 'remotes/thuth-gitlab/tags/pull-request-2021-03-12' into staging
* Move unit and bench tests into separate directories * Clean-up and improve gitlab-ci jobs * Drop the non-working "check-speed" makefile target * Minor documentation updates # gpg: Signature made Fri 12 Mar 2021 17:18:45 GMT # gpg: using RSA key 27B88847EEE0250118F3EAB92ED9D774FE702DB5 # gpg: issuer "thuth@redhat.com" # gpg: Good signature from "Thomas Huth <th.huth@gmx.de>" [full] # gpg: aka "Thomas Huth <thuth@redhat.com>" [full] # gpg: aka "Thomas Huth <huth@tuxfamily.org>" [full] # gpg: aka "Thomas Huth <th.huth@posteo.de>" [unknown] # Primary key fingerprint: 27B8 8847 EEE0 2501 18F3 EAB9 2ED9 D774 FE70 2DB5 * remotes/thuth-gitlab/tags/pull-request-2021-03-12: README: Add Documentation blurb MAINTAINERS: Merge the Gitlab-CI section into the generic CI section tests: remove "make check-speed" in favor of "make bench" gitlab-ci.yml: Merge check-crypto-old jobs into the build-crypto-old jobs gitlab-ci.yml: Merge one of the coroutine jobs with the tcg-disabled job gitlab-ci.yml: Add some missing dependencies to the jobs gitlab-ci.yml: Move build-tools-and-docs-debian to a better place tests: Move benchmarks into a separate folder tests: Move unit tests into a separate directory Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests/unit/socket-helpers.c')
-rw-r--r--tests/unit/socket-helpers.c157
1 files changed, 157 insertions, 0 deletions
diff --git a/tests/unit/socket-helpers.c b/tests/unit/socket-helpers.c
new file mode 100644
index 0000000000..f704fd1a69
--- /dev/null
+++ b/tests/unit/socket-helpers.c
@@ -0,0 +1,157 @@
+/*
+ * 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 <http://www.gnu.org/licenses/>.
+ *
+ */
+
+#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
+
+/*
+ * @hostname: a DNS name or numeric IP address
+ *
+ * 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
+ */
+static int socket_can_bind_connect(const char *hostname, int family)
+{
+ int lfd = -1, cfd = -1, afd = -1;
+ struct addrinfo ai, *res = NULL;
+ struct sockaddr_storage ss;
+ socklen_t sslen = sizeof(ss);
+ int soerr;
+ socklen_t soerrlen = sizeof(soerr);
+ bool check_soerr = false;
+ int rc;
+ int ret = -1;
+
+ memset(&ai, 0, sizeof(ai));
+ ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
+ ai.ai_family = family;
+ ai.ai_socktype = SOCK_STREAM;
+
+ /* lookup */
+ rc = getaddrinfo(hostname, NULL, &ai, &res);
+ if (rc != 0) {
+ if (rc == EAI_ADDRFAMILY || rc == EAI_FAMILY || rc == EAI_NONAME) {
+ errno = EADDRNOTAVAIL;
+ } else {
+ errno = EINVAL;
+ }
+ goto cleanup;
+ }
+
+ lfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (lfd < 0) {
+ goto cleanup;
+ }
+
+ cfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
+ if (cfd < 0) {
+ goto cleanup;
+ }
+
+ 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 == EINPROGRESS) {
+ check_soerr = true;
+ } else {
+ goto cleanup;
+ }
+ }
+
+ sslen = sizeof(ss);
+ afd = 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 = soerr;
+ goto cleanup;
+ }
+ }
+
+ ret = 0;
+
+ cleanup:
+ if (afd != -1) {
+ close(afd);
+ }
+ if (cfd != -1) {
+ close(cfd);
+ }
+ if (lfd != -1) {
+ close(lfd);
+ }
+ if (res) {
+ freeaddrinfo(res);
+ }
+ return ret;
+}
+
+
+int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
+{
+ *has_ipv4 = *has_ipv6 = false;
+
+ if (socket_can_bind_connect("127.0.0.1", PF_INET) < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ return -1;
+ }
+ } else {
+ *has_ipv4 = true;
+ }
+
+ if (socket_can_bind_connect("::1", PF_INET6) < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ return -1;
+ }
+ } else {
+ *has_ipv6 = true;
+ }
+
+ return 0;
+}