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 */ 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 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 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