blockdev: convert qemu-nbd server to QIONetListener

Instead of creating a QIOChannelSocket directly for the NBD
server socket, use a QIONetListener. This provides the ability
to listen on multiple sockets at the same time, so enables
full support for IPv4/IPv6 dual stack. This also means we can
honour multiple FDs received during socket activation.

Reviewed-by: Eric Blake <eblake@redhat.com>
Signed-off-by: Daniel P. Berrange <berrange@redhat.com>
Message-Id: <20171218101643.20360-3-berrange@redhat.com>
Signed-off-by: Paolo Bonzini <pbonzini@redhat.com>
master
Daniel P. Berrange 2017-12-18 10:16:43 +00:00 committed by Paolo Bonzini
parent 862172f45c
commit e4849c1d7c
1 changed files with 24 additions and 37 deletions

View File

@ -37,6 +37,7 @@
#include "qapi/qmp/qstring.h" #include "qapi/qmp/qstring.h"
#include "qom/object_interfaces.h" #include "qom/object_interfaces.h"
#include "io/channel-socket.h" #include "io/channel-socket.h"
#include "io/net-listener.h"
#include "crypto/init.h" #include "crypto/init.h"
#include "trace/control.h" #include "trace/control.h"
#include "qemu-version.h" #include "qemu-version.h"
@ -62,8 +63,7 @@ static int persistent = 0;
static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state; static enum { RUNNING, TERMINATE, TERMINATING, TERMINATED } state;
static int shared = 1; static int shared = 1;
static int nb_fds; static int nb_fds;
static QIOChannelSocket *server_ioc; static QIONetListener *server;
static int server_watch = -1;
static QCryptoTLSCreds *tlscreds; static QCryptoTLSCreds *tlscreds;
static void usage(const char *name) static void usage(const char *name)
@ -344,44 +344,25 @@ static void nbd_client_closed(NBDClient *client, bool negotiated)
nbd_client_put(client); nbd_client_put(client);
} }
static gboolean nbd_accept(QIOChannel *ioc, GIOCondition cond, gpointer opaque) static void nbd_accept(QIONetListener *listener, QIOChannelSocket *cioc,
gpointer opaque)
{ {
QIOChannelSocket *cioc;
cioc = qio_channel_socket_accept(QIO_CHANNEL_SOCKET(ioc),
NULL);
if (!cioc) {
return TRUE;
}
if (state >= TERMINATE) { if (state >= TERMINATE) {
object_unref(OBJECT(cioc)); return;
return TRUE;
} }
nb_fds++; nb_fds++;
nbd_update_server_watch(); nbd_update_server_watch();
nbd_client_new(newproto ? NULL : exp, cioc, nbd_client_new(newproto ? NULL : exp, cioc,
tlscreds, NULL, nbd_client_closed); tlscreds, NULL, nbd_client_closed);
object_unref(OBJECT(cioc));
return TRUE;
} }
static void nbd_update_server_watch(void) static void nbd_update_server_watch(void)
{ {
if (nbd_can_accept()) { if (nbd_can_accept()) {
if (server_watch == -1) { qio_net_listener_set_client_func(server, nbd_accept, NULL, NULL);
server_watch = qio_channel_add_watch(QIO_CHANNEL(server_ioc),
G_IO_IN,
nbd_accept,
NULL, NULL);
}
} else { } else {
if (server_watch != -1) { qio_net_listener_set_client_func(server, NULL, NULL, NULL);
g_source_remove(server_watch);
server_watch = -1;
}
} }
} }
@ -915,24 +896,30 @@ int main(int argc, char **argv)
snprintf(sockpath, 128, SOCKET_PATH, basename(device)); snprintf(sockpath, 128, SOCKET_PATH, basename(device));
} }
server = qio_net_listener_new();
if (socket_activation == 0) { if (socket_activation == 0) {
server_ioc = qio_channel_socket_new();
saddr = nbd_build_socket_address(sockpath, bindto, port); saddr = nbd_build_socket_address(sockpath, bindto, port);
if (qio_channel_socket_listen_sync(server_ioc, saddr, &local_err) < 0) { if (qio_net_listener_open_sync(server, saddr, &local_err) < 0) {
object_unref(OBJECT(server_ioc)); object_unref(OBJECT(server));
error_report_err(local_err); error_report_err(local_err);
return 1; exit(EXIT_FAILURE);
} }
} else { } else {
size_t i;
/* See comment in check_socket_activation above. */ /* See comment in check_socket_activation above. */
assert(socket_activation == 1); for (i = 0; i < socket_activation; i++) {
server_ioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD, QIOChannelSocket *sioc;
sioc = qio_channel_socket_new_fd(FIRST_SOCKET_ACTIVATION_FD + i,
&local_err); &local_err);
if (server_ioc == NULL) { if (sioc == NULL) {
object_unref(OBJECT(server));
error_report("Failed to use socket activation: %s", error_report("Failed to use socket activation: %s",
error_get_pretty(local_err)); error_get_pretty(local_err));
exit(EXIT_FAILURE); exit(EXIT_FAILURE);
} }
qio_net_listener_add(server, sioc);
object_unref(OBJECT(sioc));
}
} }
if (qemu_init_main_loop(&local_err)) { if (qemu_init_main_loop(&local_err)) {