summaryrefslogtreecommitdiffstats
path: root/tests/socket-helpers.c
diff options
context:
space:
mode:
authorPeter Maydell2018-03-15 19:53:07 +0100
committerPeter Maydell2018-03-15 19:53:07 +0100
commit58888f8cdd198affa454f9bf664a076f5f63a6a6 (patch)
tree6ac4f771973b9fabff6cd147008fad248cc683c2 /tests/socket-helpers.c
parentMerge remote-tracking branch 'remotes/vivier2/tags/linux-user-for-2.12-pull-r... (diff)
parentchar: allow passing pre-opened socket file descriptor at startup (diff)
downloadqemu-58888f8cdd198affa454f9bf664a076f5f63a6a6.tar.gz
qemu-58888f8cdd198affa454f9bf664a076f5f63a6a6.tar.xz
qemu-58888f8cdd198affa454f9bf664a076f5f63a6a6.zip
Merge remote-tracking branch 'remotes/berrange/tags/socket-next-pull-request' into staging
# gpg: Signature made Tue 13 Mar 2018 18:12:14 GMT # gpg: using RSA key BE86EBB415104FDF # gpg: Good signature from "Daniel P. Berrange <dan@berrange.com>" # gpg: aka "Daniel P. Berrange <berrange@redhat.com>" # Primary key fingerprint: DAF3 A6FD B26B 6291 2D0E 8E3F BE86 EBB4 1510 4FDF * remotes/berrange/tags/socket-next-pull-request: char: allow passing pre-opened socket file descriptor at startup char: refactor parsing of socket address information sockets: allow SocketAddress 'fd' to reference numeric file descriptors sockets: check that the named file descriptor is a socket sockets: move fd_is_socket() into common sockets code sockets: strengthen test suite IP protocol availability checks sockets: pull code for testing IP availability out of specific test cutils: add qemu_strtoi & qemu_strtoui parsers for int/unsigned int types char: don't silently skip tn3270 protocol init when TLS is enabled Signed-off-by: Peter Maydell <peter.maydell@linaro.org>
Diffstat (limited to 'tests/socket-helpers.c')
-rw-r--r--tests/socket-helpers.c149
1 files changed, 149 insertions, 0 deletions
diff --git a/tests/socket-helpers.c b/tests/socket-helpers.c
new file mode 100644
index 0000000000..8112763f5b
--- /dev/null
+++ b/tests/socket-helpers.c
@@ -0,0 +1,149 @@
+/*
+ * 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
+
+int socket_can_bind_connect(const char *hostname)
+{
+ 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 = AF_UNSPEC;
+ ai.ai_socktype = SOCK_STREAM;
+
+ /* lookup */
+ rc = getaddrinfo(hostname, NULL, &ai, &res);
+ if (rc != 0) {
+ if (rc == EAI_ADDRFAMILY ||
+ rc == EAI_FAMILY) {
+ 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") < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ return -1;
+ }
+ } else {
+ *has_ipv4 = true;
+ }
+
+ if (socket_can_bind_connect("::1") < 0) {
+ if (errno != EADDRNOTAVAIL) {
+ return -1;
+ }
+ } else {
+ *has_ipv6 = true;
+ }
+
+ return 0;
+}