19b589ffbSDaniel P. Berrange /*
29b589ffbSDaniel P. Berrange * Helper functions for tests using sockets
39b589ffbSDaniel P. Berrange *
49b589ffbSDaniel P. Berrange * Copyright 2015-2018 Red Hat, Inc.
59b589ffbSDaniel P. Berrange *
69b589ffbSDaniel P. Berrange * This program is free software; you can redistribute it and/or
79b589ffbSDaniel P. Berrange * modify it under the terms of the GNU General Public License as
89b589ffbSDaniel P. Berrange * published by the Free Software Foundation; either version 2 or
99b589ffbSDaniel P. Berrange * (at your option) version 3 of the License.
109b589ffbSDaniel P. Berrange *
119b589ffbSDaniel P. Berrange * This program is distributed in the hope that it will be useful,
129b589ffbSDaniel P. Berrange * but WITHOUT ANY WARRANTY; without even the implied warranty of
139b589ffbSDaniel P. Berrange * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
149b589ffbSDaniel P. Berrange * GNU General Public License for more details.
159b589ffbSDaniel P. Berrange *
169b589ffbSDaniel P. Berrange * You should have received a copy of the GNU General Public License
179b589ffbSDaniel P. Berrange * along with this program; if not, see <http://www.gnu.org/licenses/>.
189b589ffbSDaniel P. Berrange *
199b589ffbSDaniel P. Berrange */
209b589ffbSDaniel P. Berrange
219b589ffbSDaniel P. Berrange #include "qemu/osdep.h"
229b589ffbSDaniel P. Berrange #include "qemu/sockets.h"
239b589ffbSDaniel P. Berrange #include "socket-helpers.h"
249b589ffbSDaniel P. Berrange
259b589ffbSDaniel P. Berrange #ifndef AI_ADDRCONFIG
269b589ffbSDaniel P. Berrange # define AI_ADDRCONFIG 0
279b589ffbSDaniel P. Berrange #endif
289b589ffbSDaniel P. Berrange #ifndef EAI_ADDRFAMILY
299b589ffbSDaniel P. Berrange # define EAI_ADDRFAMILY 0
309b589ffbSDaniel P. Berrange #endif
319b589ffbSDaniel P. Berrange
3271714178SMarc-André Lureau /*
3371714178SMarc-André Lureau * @hostname: a DNS name or numeric IP address
3471714178SMarc-André Lureau *
3571714178SMarc-André Lureau * Check whether it is possible to bind & connect to ports
3671714178SMarc-André Lureau * on the DNS name or IP address @hostname. If an IP address
3771714178SMarc-André Lureau * is used, it must not be a wildcard address.
3871714178SMarc-André Lureau *
3971714178SMarc-André Lureau * Returns 0 on success, -1 on error with errno set
4071714178SMarc-André Lureau */
socket_can_bind_connect(const char * hostname,int family)4171714178SMarc-André Lureau static int socket_can_bind_connect(const char *hostname, int family)
429b589ffbSDaniel P. Berrange {
43abd983c0SDaniel P. Berrange int lfd = -1, cfd = -1, afd = -1;
449b589ffbSDaniel P. Berrange struct addrinfo ai, *res = NULL;
45abd983c0SDaniel P. Berrange struct sockaddr_storage ss;
46abd983c0SDaniel P. Berrange socklen_t sslen = sizeof(ss);
47abd983c0SDaniel P. Berrange int soerr;
48abd983c0SDaniel P. Berrange socklen_t soerrlen = sizeof(soerr);
49abd983c0SDaniel P. Berrange bool check_soerr = false;
509b589ffbSDaniel P. Berrange int rc;
519b589ffbSDaniel P. Berrange int ret = -1;
529b589ffbSDaniel P. Berrange
539b589ffbSDaniel P. Berrange memset(&ai, 0, sizeof(ai));
549b589ffbSDaniel P. Berrange ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG;
5571714178SMarc-André Lureau ai.ai_family = family;
569b589ffbSDaniel P. Berrange ai.ai_socktype = SOCK_STREAM;
579b589ffbSDaniel P. Berrange
589b589ffbSDaniel P. Berrange /* lookup */
599b589ffbSDaniel P. Berrange rc = getaddrinfo(hostname, NULL, &ai, &res);
609b589ffbSDaniel P. Berrange if (rc != 0) {
61b822c05bSThomas Huth if (rc == EAI_ADDRFAMILY || rc == EAI_FAMILY || rc == EAI_NONAME) {
629b589ffbSDaniel P. Berrange errno = EADDRNOTAVAIL;
639b589ffbSDaniel P. Berrange } else {
649b589ffbSDaniel P. Berrange errno = EINVAL;
659b589ffbSDaniel P. Berrange }
669b589ffbSDaniel P. Berrange goto cleanup;
679b589ffbSDaniel P. Berrange }
689b589ffbSDaniel P. Berrange
69abd983c0SDaniel P. Berrange lfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
70abd983c0SDaniel P. Berrange if (lfd < 0) {
719b589ffbSDaniel P. Berrange goto cleanup;
729b589ffbSDaniel P. Berrange }
739b589ffbSDaniel P. Berrange
74abd983c0SDaniel P. Berrange cfd = qemu_socket(res->ai_family, res->ai_socktype, res->ai_protocol);
75abd983c0SDaniel P. Berrange if (cfd < 0) {
769b589ffbSDaniel P. Berrange goto cleanup;
779b589ffbSDaniel P. Berrange }
789b589ffbSDaniel P. Berrange
79abd983c0SDaniel P. Berrange if (bind(lfd, res->ai_addr, res->ai_addrlen) < 0) {
80abd983c0SDaniel P. Berrange goto cleanup;
81abd983c0SDaniel P. Berrange }
82abd983c0SDaniel P. Berrange
83abd983c0SDaniel P. Berrange if (listen(lfd, 1) < 0) {
84abd983c0SDaniel P. Berrange goto cleanup;
85abd983c0SDaniel P. Berrange }
86abd983c0SDaniel P. Berrange
87abd983c0SDaniel P. Berrange if (getsockname(lfd, (struct sockaddr *)&ss, &sslen) < 0) {
88abd983c0SDaniel P. Berrange goto cleanup;
89abd983c0SDaniel P. Berrange }
90abd983c0SDaniel P. Berrange
91ff5927baSMarc-André Lureau qemu_socket_set_nonblock(cfd);
92abd983c0SDaniel P. Berrange if (connect(cfd, (struct sockaddr *)&ss, sslen) < 0) {
93abd983c0SDaniel P. Berrange if (errno == EINPROGRESS) {
94abd983c0SDaniel P. Berrange check_soerr = true;
95abd983c0SDaniel P. Berrange } else {
96abd983c0SDaniel P. Berrange goto cleanup;
97abd983c0SDaniel P. Berrange }
98abd983c0SDaniel P. Berrange }
99abd983c0SDaniel P. Berrange
100abd983c0SDaniel P. Berrange sslen = sizeof(ss);
101abd983c0SDaniel P. Berrange afd = accept(lfd, (struct sockaddr *)&ss, &sslen);
102abd983c0SDaniel P. Berrange if (afd < 0) {
103abd983c0SDaniel P. Berrange goto cleanup;
104abd983c0SDaniel P. Berrange }
105abd983c0SDaniel P. Berrange
106abd983c0SDaniel P. Berrange if (check_soerr) {
107e7b79428SMarc-André Lureau if (getsockopt(cfd, SOL_SOCKET, SO_ERROR, &soerr, &soerrlen) < 0) {
108abd983c0SDaniel P. Berrange goto cleanup;
109abd983c0SDaniel P. Berrange }
110abd983c0SDaniel P. Berrange if (soerr) {
111abd983c0SDaniel P. Berrange errno = soerr;
112abd983c0SDaniel P. Berrange goto cleanup;
113abd983c0SDaniel P. Berrange }
114abd983c0SDaniel P. Berrange }
115abd983c0SDaniel P. Berrange
1169b589ffbSDaniel P. Berrange ret = 0;
1179b589ffbSDaniel P. Berrange
1189b589ffbSDaniel P. Berrange cleanup:
119abd983c0SDaniel P. Berrange if (afd != -1) {
12025657fc6SMarc-André Lureau close(afd);
121abd983c0SDaniel P. Berrange }
122abd983c0SDaniel P. Berrange if (cfd != -1) {
12325657fc6SMarc-André Lureau close(cfd);
124abd983c0SDaniel P. Berrange }
125abd983c0SDaniel P. Berrange if (lfd != -1) {
12625657fc6SMarc-André Lureau close(lfd);
1279b589ffbSDaniel P. Berrange }
1289b589ffbSDaniel P. Berrange if (res) {
1299b589ffbSDaniel P. Berrange freeaddrinfo(res);
1309b589ffbSDaniel P. Berrange }
1319b589ffbSDaniel P. Berrange return ret;
1329b589ffbSDaniel P. Berrange }
1339b589ffbSDaniel P. Berrange
1349b589ffbSDaniel P. Berrange
socket_check_protocol_support(bool * has_ipv4,bool * has_ipv6)1359b589ffbSDaniel P. Berrange int socket_check_protocol_support(bool *has_ipv4, bool *has_ipv6)
1369b589ffbSDaniel P. Berrange {
1379b589ffbSDaniel P. Berrange *has_ipv4 = *has_ipv6 = false;
1389b589ffbSDaniel P. Berrange
13971714178SMarc-André Lureau if (socket_can_bind_connect("127.0.0.1", PF_INET) < 0) {
1409b589ffbSDaniel P. Berrange if (errno != EADDRNOTAVAIL) {
1419b589ffbSDaniel P. Berrange return -1;
1429b589ffbSDaniel P. Berrange }
1439b589ffbSDaniel P. Berrange } else {
1449b589ffbSDaniel P. Berrange *has_ipv4 = true;
1459b589ffbSDaniel P. Berrange }
1469b589ffbSDaniel P. Berrange
14771714178SMarc-André Lureau if (socket_can_bind_connect("::1", PF_INET6) < 0) {
1489b589ffbSDaniel P. Berrange if (errno != EADDRNOTAVAIL) {
1499b589ffbSDaniel P. Berrange return -1;
1509b589ffbSDaniel P. Berrange }
1519b589ffbSDaniel P. Berrange } else {
1529b589ffbSDaniel P. Berrange *has_ipv6 = true;
1539b589ffbSDaniel P. Berrange }
1549b589ffbSDaniel P. Berrange
1559b589ffbSDaniel P. Berrange return 0;
1569b589ffbSDaniel P. Berrange }
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 }
174