@@ -34,6 +34,12 @@ int inet_ai_family_from_address(InetSocketAddress *addr,
int inet_parse(InetSocketAddress *addr, const char *str, Error **errp);
int inet_connect(const char *str, Error **errp);
int inet_connect_saddr(InetSocketAddress *saddr, Error **errp);
+int inet_connect_addr(InetSocketAddress *saddr, struct addrinfo *addr,
+ bool blocking, bool *in_progress, Error **errp);
+struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr,
+ Error **errp);
+
+int socket_check(int fd, Error **errp);
NetworkAddressFamily inet_netfamily(int family);
@@ -354,11 +354,17 @@ listen_ok:
((rc) == -EINPROGRESS)
#endif
-static int inet_connect_addr(InetSocketAddress *saddr,
- struct addrinfo *addr, Error **errp)
+int inet_connect_addr(InetSocketAddress *saddr, struct addrinfo *addr,
+ bool blocking, bool *in_progress, Error **errp)
{
int sock, rc;
+ assert(blocking == !in_progress);
+
+ if (in_progress) {
+ *in_progress = false;
+ }
+
sock = qemu_socket(addr->ai_family, addr->ai_socktype, addr->ai_protocol);
if (sock < 0) {
error_setg_errno(errp, errno, "Failed to create socket");
@@ -366,6 +372,10 @@ static int inet_connect_addr(InetSocketAddress *saddr,
}
socket_set_fast_reuse(sock);
+ if (!blocking) {
+ qemu_set_nonblock(sock);
+ }
+
/* connect to peer */
do {
rc = 0;
@@ -374,6 +384,13 @@ static int inet_connect_addr(InetSocketAddress *saddr,
}
} while (rc == -EINTR);
+ if (!blocking && rc == -EINPROGRESS) {
+ if (in_progress) {
+ *in_progress = true;
+ }
+ return sock;
+ }
+
if (rc < 0) {
error_setg_errno(errp, errno, "Failed to connect socket");
closesocket(sock);
@@ -395,8 +412,26 @@ static int inet_connect_addr(InetSocketAddress *saddr,
return sock;
}
-static struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr,
- Error **errp)
+int socket_check(int fd, Error **errp)
+{
+ int optval;
+ socklen_t optlen = sizeof(optval);
+ if (qemu_getsockopt(fd, SOL_SOCKET, SO_ERROR, &optval, &optlen) < 0) {
+ error_setg_errno(errp, errno, "Unable to check connection");
+ return -1;
+ }
+
+ if (optval != 0) {
+ error_setg_errno(errp, errno, "Connection failed");
+ return -1;
+ }
+
+ return 0;
+}
+
+
+struct addrinfo *inet_parse_connect_saddr(InetSocketAddress *saddr,
+ Error **errp)
{
struct addrinfo ai, *res;
int rc;
@@ -466,7 +501,7 @@ int inet_connect_saddr(InetSocketAddress *saddr, Error **errp)
for (e = res; e != NULL; e = e->ai_next) {
error_free(local_err);
local_err = NULL;
- sock = inet_connect_addr(saddr, e, &local_err);
+ sock = inet_connect_addr(saddr, e, true, NULL, &local_err);
if (sock >= 0) {
break;
}
We are going to implement non-blocking connect in io/channel-socket. non-blocking connect includes three phases: 1. connect() call 2. wait until socket is ready 3. check result io/channel-socket has wait-on-socket API (qio_channel_yield(), qio_channel_wait()), so it's a good place for [2]. Still, the whole thing is not simple, because socket connect in case of inet socket includes several connect() calls, as SocketAddress may be parsed into a list of inet addresses. And after each non-blocking connect() upper layer should have a possibility to wait on the socket. We may try to implement a kind of abstract list or iterator for "sub" addresses of SocketAddress, but all this appears to be too complex and not worth doing (as actually, only inet sockets has such a "multiple" SocketAddress). So, let's instead make public API for inet sockets themselves, to be handled in separate in upper layer, if it needs non-blocking connect. Signed-off-by: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com> --- include/qemu/sockets.h | 6 ++++++ util/qemu-sockets.c | 45 +++++++++++++++++++++++++++++++++++++----- 2 files changed, 46 insertions(+), 5 deletions(-)