1da668aa1SThomas Huth /*
2da668aa1SThomas Huth * Helper functions for tests using sockets
3da668aa1SThomas Huth *
4da668aa1SThomas Huth * Copyright 2015-2018 Red Hat, Inc.
5da668aa1SThomas Huth *
6da668aa1SThomas Huth * This program is free software; you can redistribute it and/or
7da668aa1SThomas Huth * modify it under the terms of the GNU General Public License as
8da668aa1SThomas Huth * published by the Free Software Foundation; either version 2 or
9da668aa1SThomas Huth * (at your option) version 3 of the License.
10da668aa1SThomas Huth *
11da668aa1SThomas Huth * This program is distributed in the hope that it will be useful,
12da668aa1SThomas Huth * but WITHOUT ANY WARRANTY; without even the implied warranty of
13da668aa1SThomas Huth * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
14da668aa1SThomas Huth * GNU General Public License for more details.
15da668aa1SThomas Huth *
16da668aa1SThomas Huth * You should have received a copy of the GNU General Public License
17da668aa1SThomas Huth * along with this program; if not, see <http://www.gnu.org/licenses/>.
18da668aa1SThomas Huth *
19da668aa1SThomas Huth */
20da668aa1SThomas Huth
21da668aa1SThomas Huth #include "qemu/osdep.h"
22da668aa1SThomas Huth #include "qemu/sockets.h"
23da668aa1SThomas Huth #include "socket-helpers.h"
24da668aa1SThomas Huth
25da668aa1SThomas Huth #ifndef AI_ADDRCONFIG
26da668aa1SThomas Huth # define AI_ADDRCONFIG 0
27da668aa1SThomas Huth #endif
28da668aa1SThomas Huth #ifndef EAI_ADDRFAMILY
29da668aa1SThomas Huth # define EAI_ADDRFAMILY 0
30da668aa1SThomas Huth #endif
31da668aa1SThomas Huth
32da668aa1SThomas Huth /*
33da668aa1SThomas Huth * @hostname: a DNS name or numeric IP address
34da668aa1SThomas Huth *
35da668aa1SThomas Huth * Check whether it is possible to bind & connect to ports
36da668aa1SThomas Huth * on the DNS name or IP address @hostname. If an IP address
37da668aa1SThomas Huth * is used, it must not be a wildcard address.
38da668aa1SThomas Huth *
39da668aa1SThomas Huth * Returns 0 on success, -1 on error with errno set
40da668aa1SThomas Huth */
socket_can_bind_connect(const char * hostname,int family)41da668aa1SThomas Huth static int socket_can_bind_connect(const char *hostname, int family)
42da668aa1SThomas Huth {
43da668aa1SThomas Huth int lfd = -1, cfd = -1, afd = -1;
44da668aa1SThomas Huth struct addrinfo ai, *res = NULL;
45da668aa1SThomas Huth struct sockaddr_storage ss;
46da668aa1SThomas Huth socklen_t sslen = sizeof(ss);
47da668aa1SThomas Huth int soerr;
48da668aa1SThomas Huth socklen_t soerrlen = sizeof(soerr);
49da668aa1SThomas Huth bool check_soerr = false;
50da668aa1SThomas Huth int rc;
51da668aa1SThomas Huth int ret = -1;
52da668aa1SThomas Huth
53da668aa1SThomas Huth memset(&ai, 0, sizeof(ai));
54da668aa1SThomas Huth ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
55da668aa1SThomas Huth ai.ai_family = family;
56da668aa1SThomas Huth ai.ai_socktype = SOCK_STREAM;
57da668aa1SThomas Huth
58da668aa1SThomas Huth /* lookup */
59da668aa1SThomas Huth rc = getaddrinfo(hostname, NULL, &ai, &res);
60da668aa1SThomas Huth if (rc != 0) {
61da668aa1SThomas Huth if (rc == EAI_ADDRFAMILY || rc == EAI_FAMILY || rc == EAI_NONAME) {
62da668aa1SThomas Huth errno = EADDRNOTAVAIL;
63da668aa1SThomas Huth } else {
64da668aa1SThomas Huth errno = EINVAL;
65da668aa1SThomas Huth }
66da668aa1SThomas Huth goto cleanup;
67da668aa1SThomas Huth }
68da668aa1SThomas Huth
69da668aa1SThomas Huth lfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
70da668aa1SThomas Huth if (lfd < 0) {
71da668aa1SThomas Huth goto cleanup;
72da668aa1SThomas Huth }
73da668aa1SThomas Huth
74da668aa1SThomas Huth cfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
75da668aa1SThomas Huth if (cfd < 0) {
76da668aa1SThomas Huth goto cleanup;
77da668aa1SThomas Huth }
78da668aa1SThomas Huth
79da668aa1SThomas Huth if (bind(lfd, res->ai_addr, res->ai_addrlen) < 0) {
80da668aa1SThomas Huth goto cleanup;
81da668aa1SThomas Huth }
82da668aa1SThomas Huth
83da668aa1SThomas Huth if (listen(lfd, 1) < 0) {
84da668aa1SThomas Huth goto cleanup;
85da668aa1SThomas Huth }
86da668aa1SThomas Huth
87da668aa1SThomas Huth if (getsockname(lfd, (struct sockaddr *)&ss, &sslen) < 0) {
88da668aa1SThomas Huth goto cleanup;
89da668aa1SThomas Huth }
90da668aa1SThomas Huth
91ff5927baSMarc-André Lureau qemu_socket_set_nonblock(cfd);
92da668aa1SThomas Huth if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) {
93da668aa1SThomas Huth if (errno == EINPROGRESS) {
94da668aa1SThomas Huth check_soerr = true;
95da668aa1SThomas Huth } else {
96da668aa1SThomas Huth goto cleanup;
97da668aa1SThomas Huth }
98da668aa1SThomas Huth }
99da668aa1SThomas Huth
100da668aa1SThomas Huth sslen = sizeof(ss);
101da668aa1SThomas Huth afd = accept(lfd, (struct sockaddr *)&ss, &sslen);
102da668aa1SThomas Huth if (afd < 0) {
103da668aa1SThomas Huth goto cleanup;
104da668aa1SThomas Huth }
105da668aa1SThomas Huth
106da668aa1SThomas Huth if (check_soerr) {
107e7b79428SMarc-André Lureau if (getsockopt(cfd, SOL_SOCKET, SO_ERROR, &soerr, &soerrlen) < 0) {
108da668aa1SThomas Huth goto cleanup;
109da668aa1SThomas Huth }
110da668aa1SThomas Huth if (soerr) {
111da668aa1SThomas Huth errno = soerr;
112da668aa1SThomas Huth goto cleanup;
113da668aa1SThomas Huth }
114da668aa1SThomas Huth }
115da668aa1SThomas Huth
116da668aa1SThomas Huth ret = 0;
117da668aa1SThomas Huth
118da668aa1SThomas Huth cleanup:
119da668aa1SThomas Huth if (afd != -1) {
12025657fc6SMarc-André Lureau close(afd);
121da668aa1SThomas Huth }
122da668aa1SThomas Huth if (cfd != -1) {
12325657fc6SMarc-André Lureau close(cfd);
124da668aa1SThomas Huth }
125da668aa1SThomas Huth if (lfd != -1) {
12625657fc6SMarc-André Lureau close(lfd);
127da668aa1SThomas Huth }
128da668aa1SThomas Huth if (res) {
129da668aa1SThomas Huth freeaddrinfo(res);
130da668aa1SThomas Huth }
131da668aa1SThomas Huth return ret;
132da668aa1SThomas Huth }
133da668aa1SThomas Huth
134da668aa1SThomas Huth
socket_check_protocol_support(bool * has_ipv4,bool * has_ipv6)135da668aa1SThomas Huth int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
136da668aa1SThomas Huth {
137da668aa1SThomas Huth *has_ipv4 = *has_ipv6 = false;
138da668aa1SThomas Huth
139da668aa1SThomas Huth if (socket_can_bind_connect("127.0.0.1", PF_INET) < 0) {
140da668aa1SThomas Huth if (errno != EADDRNOTAVAIL) {
141da668aa1SThomas Huth return -1;
142da668aa1SThomas Huth }
143da668aa1SThomas Huth } else {
144da668aa1SThomas Huth *has_ipv4 = true;
145da668aa1SThomas Huth }
146da668aa1SThomas Huth
147da668aa1SThomas Huth if (socket_can_bind_connect("::1", PF_INET6) < 0) {
148da668aa1SThomas Huth if (errno != EADDRNOTAVAIL) {
149da668aa1SThomas Huth return -1;
150da668aa1SThomas Huth }
151da668aa1SThomas Huth } else {
152da668aa1SThomas Huth *has_ipv6 = true;
153da668aa1SThomas Huth }
154da668aa1SThomas Huth
155da668aa1SThomas Huth return 0;
156da668aa1SThomas Huth }
1570370f239SBin Meng
socket_check_afunix_support(bool * has_afunix)1580370f239SBin Meng void socket_check_afunix_support(bool *has_afunix)
1590370f239SBin Meng {
1600370f239SBin Meng int fd;
1610370f239SBin Meng
1620370f239SBin Meng fd = socket(PF_UNIX, SOCK_STREAM, 0);
1630370f239SBin Meng
1640370f239SBin Meng #ifdef _WIN32
1650370f239SBin Meng *has_afunix = (fd != (int)INVALID_SOCKET);
1660370f239SBin Meng #else
1670370f239SBin Meng *has_afunix = (fd >= 0);
1680370f239SBin Meng #endif
1690370f239SBin Meng
170*e921e00dSPeter Maydell if (*has_afunix) {
171*e921e00dSPeter Maydell close(fd);
172*e921e00dSPeter Maydell }
1730370f239SBin Meng return;
1740370f239SBin Meng }
175