static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, Error **errp) { struct addrinfo ai, *res; int rc; Error *err = NULL; memset(&ai, 0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; if (err) { error_propagate(errp, err); return NULL; } if (saddr->host == NULL || saddr->port == NULL) { error_setg(errp, "host and/or port not specified"); return NULL; } /* lookup */ rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", saddr->host, saddr->port, gai_strerror(rc)); return NULL; } return res; }
static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr, Error **errp) { struct addrinfo ai, *res; int rc; Error *err = NULL; static int useV4Mapped = 1; memset(&ai, 0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_ADDRCONFIG; if (atomic_read(&useV4Mapped)) { ai.ai_flags |= AI_V4MAPPED; } ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; if (err) { error_propagate(errp, err); return NULL; } if (saddr->host == NULL || saddr->port == NULL) { error_setg(errp, "host and/or port not specified"); return NULL; } /* lookup */ rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); /* At least FreeBSD and OS-X 10.6 declare AI_V4MAPPED but * then don't implement it in their getaddrinfo(). Detect * this and retry without the flag since that's preferrable * to a fatal error */ if (rc == EAI_BADFLAGS && (ai.ai_flags & AI_V4MAPPED)) { atomic_set(&useV4Mapped, 0); ai.ai_flags &= ~AI_V4MAPPED; rc = getaddrinfo(saddr->host, saddr->port, &ai, &res); } if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", saddr->host, saddr->port, gai_strerror(rc)); return NULL; } return res; }
static int inet_dgram_saddr(InetSocketAddress *sraddr, InetSocketAddress *sladdr, Error **errp) { struct addrinfo ai, *peer = NULL, *local = NULL; const char *addr; const char *port; int sock = -1, rc; Error *err = NULL; /* lookup peer addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_CANONNAME | AI_V4MAPPED | AI_ADDRCONFIG; ai.ai_family = inet_ai_family_from_address(sraddr, &err); ai.ai_socktype = SOCK_DGRAM; if (err) { error_propagate(errp, err); goto err; } addr = sraddr->host; port = sraddr->port; if (addr == NULL || strlen(addr) == 0) { addr = "localhost"; } if (port == NULL || strlen(port) == 0) { error_setg(errp, "remote port not specified"); goto err; } if ((rc = getaddrinfo(addr, port, &ai, &peer)) != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); goto err; } /* lookup local addr */ memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; ai.ai_family = peer->ai_family; ai.ai_socktype = SOCK_DGRAM; if (sladdr) { addr = sladdr->host; port = sladdr->port; if (addr == NULL || strlen(addr) == 0) { addr = NULL; } if (!port || strlen(port) == 0) { port = "0"; } } else { addr = NULL; port = "0"; } if ((rc = getaddrinfo(addr, port, &ai, &local)) != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", addr, port, gai_strerror(rc)); goto err; } /* create socket */ sock = qemu_socket(peer->ai_family, peer->ai_socktype, peer->ai_protocol); if (sock < 0) { error_setg_errno(errp, errno, "Failed to create socket"); goto err; } socket_set_fast_reuse(sock); /* bind socket */ if (bind(sock, local->ai_addr, local->ai_addrlen) < 0) { error_setg_errno(errp, errno, "Failed to bind socket"); goto err; } /* connect to peer */ if (connect(sock,peer->ai_addr,peer->ai_addrlen) < 0) { error_setg_errno(errp, errno, "Failed to connect socket"); goto err; } freeaddrinfo(local); freeaddrinfo(peer); return sock; err: if (sock != -1) { closesocket(sock); } if (local) { freeaddrinfo(local); } if (peer) { freeaddrinfo(peer); } return -1; }
static int inet_listen_saddr(InetSocketAddress *saddr, int port_offset, Error **errp) { struct addrinfo ai,*res,*e; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int rc, port_min, port_max, p; int slisten = -1; int saved_errno = 0; bool socket_created = false; Error *err = NULL; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; if (saddr->has_numeric && saddr->numeric) { ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; } ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; if (err) { error_propagate(errp, err); return -1; } if (saddr->host == NULL) { error_setg(errp, "host not specified"); return -1; } if (saddr->port != NULL) { pstrcpy(port, sizeof(port), saddr->port); } else { port[0] = '\0'; } /* lookup */ if (port_offset) { unsigned long long baseport; if (strlen(port) == 0) { error_setg(errp, "port not specified"); return -1; } if (parse_uint_full(port, &baseport, 10) < 0) { error_setg(errp, "can't convert to a number: %s", port); return -1; } if (baseport > 65535 || baseport + port_offset > 65535) { error_setg(errp, "port %s out of range", port); return -1; } snprintf(port, sizeof(port), "%d", (int)baseport + port_offset); } rc = getaddrinfo(strlen(saddr->host) ? saddr->host : NULL, strlen(port) ? port : NULL, &ai, &res); if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", saddr->host, port, gai_strerror(rc)); return -1; } /* create socket + bind/listen */ for (e = res; e != NULL; e = e->ai_next) { getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV); port_min = inet_getport(e); port_max = saddr->has_to ? saddr->to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { inet_setport(e, p); slisten = create_fast_reuse_socket(e); if (slisten < 0) { /* First time we expect we might fail to create the socket * eg if 'e' has AF_INET6 but ipv6 kmod is not loaded. * Later iterations should always succeed if first iteration * worked though, so treat that as fatal. */ if (p == port_min) { continue; } else { error_setg_errno(errp, errno, "Failed to recreate failed listening socket"); goto listen_failed; } } socket_created = true; rc = try_bind(slisten, saddr, e); if (rc < 0) { if (errno != EADDRINUSE) { error_setg_errno(errp, errno, "Failed to bind socket"); goto listen_failed; } } else { if (!listen(slisten, 1)) { goto listen_ok; } if (errno != EADDRINUSE) { error_setg_errno(errp, errno, "Failed to listen on socket"); goto listen_failed; } } /* Someone else managed to bind to the same port and beat us * to listen on it! Socket semantics does not allow us to * recover from this situation, so we need to recreate the * socket to allow bind attempts for subsequent ports: */ closesocket(slisten); slisten = -1; } } error_setg_errno(errp, errno, socket_created ? "Failed to find an available port" : "Failed to create a socket"); listen_failed: saved_errno = errno; if (slisten >= 0) { closesocket(slisten); } freeaddrinfo(res); errno = saved_errno; return -1; listen_ok: freeaddrinfo(res); return slisten; }
static int inet_listen_saddr(InetSocketAddress *saddr, int port_offset, bool update_addr, Error **errp) { struct addrinfo ai,*res,*e; char port[33]; char uaddr[INET6_ADDRSTRLEN+1]; char uport[33]; int slisten, rc, port_min, port_max, p; Error *err = NULL; memset(&ai,0, sizeof(ai)); ai.ai_flags = AI_PASSIVE; if (saddr->has_numeric && saddr->numeric) { ai.ai_flags |= AI_NUMERICHOST | AI_NUMERICSERV; } ai.ai_family = inet_ai_family_from_address(saddr, &err); ai.ai_socktype = SOCK_STREAM; if (err) { error_propagate(errp, err); return -1; } if (saddr->host == NULL) { error_setg(errp, "host not specified"); return -1; } if (saddr->port != NULL) { pstrcpy(port, sizeof(port), saddr->port); } else { port[0] = '\0'; } /* lookup */ if (port_offset) { unsigned long long baseport; if (strlen(port) == 0) { error_setg(errp, "port not specified"); return -1; } if (parse_uint_full(port, &baseport, 10) < 0) { error_setg(errp, "can't convert to a number: %s", port); return -1; } if (baseport > 65535 || baseport + port_offset > 65535) { error_setg(errp, "port %s out of range", port); return -1; } snprintf(port, sizeof(port), "%d", (int)baseport + port_offset); } rc = getaddrinfo(strlen(saddr->host) ? saddr->host : NULL, strlen(port) ? port : NULL, &ai, &res); if (rc != 0) { error_setg(errp, "address resolution failed for %s:%s: %s", saddr->host, port, gai_strerror(rc)); return -1; } /* create socket + bind */ for (e = res; e != NULL; e = e->ai_next) { getnameinfo((struct sockaddr*)e->ai_addr,e->ai_addrlen, uaddr,INET6_ADDRSTRLEN,uport,32, NI_NUMERICHOST | NI_NUMERICSERV); slisten = qemu_socket(e->ai_family, e->ai_socktype, e->ai_protocol); if (slisten < 0) { if (!e->ai_next) { error_setg_errno(errp, errno, "Failed to create socket"); } continue; } socket_set_fast_reuse(slisten); #ifdef IPV6_V6ONLY if (e->ai_family == PF_INET6) { /* listen on both ipv4 and ipv6 */ const int off = 0; qemu_setsockopt(slisten, IPPROTO_IPV6, IPV6_V6ONLY, &off, sizeof(off)); } #endif port_min = inet_getport(e); port_max = saddr->has_to ? saddr->to + port_offset : port_min; for (p = port_min; p <= port_max; p++) { inet_setport(e, p); if (bind(slisten, e->ai_addr, e->ai_addrlen) == 0) { goto listen; } if (p == port_max) { if (!e->ai_next) { error_setg_errno(errp, errno, "Failed to bind socket"); } } } closesocket(slisten); } freeaddrinfo(res); return -1; listen: if (listen(slisten,1) != 0) { error_setg_errno(errp, errno, "Failed to listen on socket"); closesocket(slisten); freeaddrinfo(res); return -1; } if (update_addr) { g_free(saddr->host); saddr->host = g_strdup(uaddr); g_free(saddr->port); saddr->port = g_strdup_printf("%d", inet_getport(e) - port_offset); saddr->has_ipv6 = saddr->ipv6 = e->ai_family == PF_INET6; saddr->has_ipv4 = saddr->ipv4 = e->ai_family != PF_INET6; } freeaddrinfo(res); return slisten; }