From: Vladimir Sementsov-Ogievskiy <vsementsov@virtuozzo.com>
To: qemu-block@nongnu.org
Cc: kwolf@redhat.com, vsementsov@virtuozzo.com, berrange@redhat.com,
qemu-devel@nongnu.org, mreitz@redhat.com, kraxel@redhat.com,
den@openvz.org
Subject: [PATCH 2/4] qemu-sockets: implement non-blocking connect interface
Date: Mon, 20 Jul 2020 21:07:13 +0300 [thread overview]
Message-ID: <20200720180715.10521-3-vsementsov@virtuozzo.com> (raw)
In-Reply-To: <20200720180715.10521-1-vsementsov@virtuozzo.com>
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
next prev parent reply other threads:[~2020-07-20 18:10 UTC|newest]
Thread overview: 17+ messages / expand[flat|nested] mbox.gz Atom feed top
2020-07-20 18:07 [PATCH for-5.1? 0/4] non-blocking connect Vladimir Sementsov-Ogievskiy
2020-07-20 18:07 ` [PATCH 1/4] qemu-sockets: refactor inet_connect_addr Vladimir Sementsov-Ogievskiy
2020-07-20 18:07 ` Vladimir Sementsov-Ogievskiy [this message]
2020-07-20 18:07 ` [PATCH 3/4] io/channel-socket: implement non-blocking connect Vladimir Sementsov-Ogievskiy
2020-07-20 18:29 ` Daniel P. Berrangé
2020-07-22 11:00 ` Vladimir Sementsov-Ogievskiy
2020-07-22 11:21 ` Daniel P. Berrangé
2020-07-22 12:43 ` Vladimir Sementsov-Ogievskiy
2020-07-22 12:53 ` Daniel P. Berrangé
2020-07-22 13:47 ` Vladimir Sementsov-Ogievskiy
2020-07-22 15:04 ` Vladimir Sementsov-Ogievskiy
2020-07-22 15:21 ` Daniel P. Berrangé
2020-07-22 15:40 ` Vladimir Sementsov-Ogievskiy
2020-07-22 15:43 ` Daniel P. Berrangé
2020-07-22 15:56 ` Vladimir Sementsov-Ogievskiy
2020-07-20 18:07 ` [PATCH 4/4] block/nbd: use non-blocking connect: fix vm hang on connect() Vladimir Sementsov-Ogievskiy
2020-07-23 19:35 ` [PATCH for-5.1? 0/4] non-blocking connect Eric Blake
Reply instructions:
You may reply publicly to this message via plain-text email
using any one of the following methods:
* Save the following mbox file, import it into your mail client,
and reply-to-all from there: mbox
Avoid top-posting and favor interleaved quoting:
https://en.wikipedia.org/wiki/Posting_style#Interleaved_style
* Reply using the --to, --cc, and --in-reply-to
switches of git-send-email(1):
git send-email \
--in-reply-to=20200720180715.10521-3-vsementsov@virtuozzo.com \
--to=vsementsov@virtuozzo.com \
--cc=berrange@redhat.com \
--cc=den@openvz.org \
--cc=kraxel@redhat.com \
--cc=kwolf@redhat.com \
--cc=mreitz@redhat.com \
--cc=qemu-block@nongnu.org \
--cc=qemu-devel@nongnu.org \
/path/to/YOUR_REPLY
https://kernel.org/pub/software/scm/git/docs/git-send-email.html
* If your mail client supports setting the In-Reply-To header
via mailto: links, try the mailto: link
Be sure your reply has a Subject: header at the top and a blank line
before the message body.
This is a public inbox, see mirroring instructions
for how to clone and mirror all data and code used for this inbox;
as well as URLs for NNTP newsgroup(s).