This eliminates the need for active waiting. Resolves: https://bugzilla.redhat.com/show_bug.cgi?id=927369 Signed-off-by: Martin Kletzander <mkletzan@xxxxxxxxxx> --- src/rpc/virnetsocket.c | 58 +++++++++++++++++++++++++++++++++----------------- 1 file changed, 39 insertions(+), 19 deletions(-) diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index a94b2bc..c00209c 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -1,7 +1,7 @@ /* * virnetsocket.c: generic network socket handling * - * Copyright (C) 2006-2013 Red Hat, Inc. + * Copyright (C) 2006-2014 Red Hat, Inc. * Copyright (C) 2006 Daniel P. Berrange * * This library is free software; you can redistribute it and/or @@ -121,7 +121,7 @@ VIR_ONCE_GLOBAL_INIT(virNetSocket) #ifndef WIN32 -static int virNetSocketForkDaemon(const char *binary) +static int virNetSocketForkDaemon(const char *binary, int passfd) { int ret; virCommandPtr cmd = virCommandNewArgList(binary, @@ -134,6 +134,10 @@ static int virNetSocketForkDaemon(const char *binary) virCommandAddEnvPassBlockSUID(cmd, "XDG_RUNTIME_DIR", NULL); virCommandClearCaps(cmd); virCommandDaemonize(cmd); + if (passfd) { + virCommandPassFD(cmd, passfd, VIR_COMMAND_PASS_FD_CLOSE_PARENT); + virCommandPassListenFDs(cmd); + } ret = virCommandRun(cmd, NULL); virCommandFree(cmd); return ret; @@ -542,8 +546,7 @@ int virNetSocketNewConnectUNIX(const char *path, { virSocketAddr localAddr; virSocketAddr remoteAddr; - int fd; - int retries = 0; + int fd, passfd; memset(&localAddr, 0, sizeof(localAddr)); memset(&remoteAddr, 0, sizeof(remoteAddr)); @@ -569,28 +572,45 @@ int virNetSocketNewConnectUNIX(const char *path, if (remoteAddr.data.un.sun_path[0] == '@') remoteAddr.data.un.sun_path[0] = '\0'; - retry: - if (connect(fd, &remoteAddr.data.sa, remoteAddr.len) < 0) { - if ((errno == ECONNREFUSED || - errno == ENOENT) && - spawnDaemon && retries < 20) { - VIR_DEBUG("Connection refused for %s, trying to spawn %s", - path, binary); - if (retries == 0 && - virNetSocketForkDaemon(binary) < 0) - goto error; + if (spawnDaemon) { + if ((passfd = socket(PF_UNIX, SOCK_STREAM, 0)) < 0) { + virReportSystemError(errno, "%s", _("Failed to create socket")); + goto error; + } - retries++; - usleep(1000 * 100 * retries); - goto retry; + /* + * We cannot do the umask() trick here because that's not + * thread-safe. fchmod(), however, is not guaranteed to work on + * some BSD favours, but *should* work on Linux before the socket + * is bound. POSIX says the behaviour of fchmod() called on + * socket is unspecified, though. + */ + if (fchmod(passfd, 0700) < 0) { + virReportSystemError(errno, "%s", + _("Failed to change permissions on socket")); + goto error; } - virReportSystemError(errno, - _("Failed to connect socket to '%s'"), + if (bind(passfd, &remoteAddr.data.sa, remoteAddr.len) < 0) { + virReportSystemError(errno, _("Failed to bind socket to %s"), path); + goto error; + } + + if (listen(passfd, 0) < 0) { + virReportSystemError(errno, "%s", _("Failed to listen on socket to")); + goto error; + } + } + + if (connect(fd, &remoteAddr.data.sa, remoteAddr.len) < 0) { + virReportSystemError(errno, _("Failed to connect socket to '%s'"), path); goto error; } + if (spawnDaemon && virNetSocketForkDaemon(binary, passfd) < 0) + goto error; + localAddr.len = sizeof(localAddr.data); if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) { virReportSystemError(errno, "%s", _("Unable to get local socket name")); -- 2.0.0 -- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list