[Date Prev][Date Next][Thread Prev][Thread Next][Date Index][Thread Index]
[PATCH 2/4] qemu-sockets: implement non-blocking connect interface
From: |
Vladimir Sementsov-Ogievskiy |
Subject: |
[PATCH 2/4] qemu-sockets: implement non-blocking connect interface |
Date: |
Mon, 20 Jul 2020 21:07:13 +0300 |
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(-)
diff --git a/include/qemu/sockets.h b/include/qemu/sockets.h
index 7d1f813576..7389d6be55 100644
--- a/include/qemu/sockets.h
+++ b/include/qemu/sockets.h
@@ -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);
diff --git a/util/qemu-sockets.c b/util/qemu-sockets.c
index 8ccf4088c2..a02d00f342 100644
--- a/util/qemu-sockets.c
+++ b/util/qemu-sockets.c
@@ -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;
}
--
2.21.0
- [PATCH for-5.1? 0/4] non-blocking connect, Vladimir Sementsov-Ogievskiy, 2020/07/20
- [PATCH 1/4] qemu-sockets: refactor inet_connect_addr, Vladimir Sementsov-Ogievskiy, 2020/07/20
- [PATCH 2/4] qemu-sockets: implement non-blocking connect interface,
Vladimir Sementsov-Ogievskiy <=
- [PATCH 3/4] io/channel-socket: implement non-blocking connect, Vladimir Sementsov-Ogievskiy, 2020/07/20
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Daniel P . Berrangé, 2020/07/20
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Vladimir Sementsov-Ogievskiy, 2020/07/22
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Daniel P . Berrangé, 2020/07/22
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Vladimir Sementsov-Ogievskiy, 2020/07/22
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Daniel P . Berrangé, 2020/07/22
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Vladimir Sementsov-Ogievskiy, 2020/07/22
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Vladimir Sementsov-Ogievskiy, 2020/07/22
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Daniel P . Berrangé, 2020/07/22
- Re: [PATCH 3/4] io/channel-socket: implement non-blocking connect, Vladimir Sementsov-Ogievskiy, 2020/07/22