This guts the current remote driver, removing all its networking
handling code. Instead it calls out to the new virClientPtr and
virClientProgramPtr APIs for all RPC & networking work.
---
src/Makefile.am | 3 +-
src/remote/remote_driver.c | 2530 ++++++++------------------------------------
2 files changed, 419 insertions(+), 2114 deletions(-)
diff --git a/src/Makefile.am b/src/Makefile.am
index 4c6efa8..8986f22 100644
--- a/src/Makefile.am
+++ b/src/Makefile.am
@@ -475,9 +475,10 @@ libvirt_driver_remote_la_CFLAGS = \
$(GNUTLS_CFLAGS) \
$(SASL_CFLAGS) \
-I@top_srcdir@/src/conf \
+ -I@top_srcdir@/src/rpc \
$(AM_CFLAGS)
libvirt_driver_remote_la_LDFLAGS = $(AM_LDFLAGS)
-libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) $(SASL_LIBS)
+libvirt_driver_remote_la_LIBADD = $(GNUTLS_LIBS) $(SASL_LIBS) libvirt-net-client.la
libvirt-net-rpc.la
if WITH_DRIVER_MODULES
libvirt_driver_remote_la_LDFLAGS += -module -avoid-version
endif
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e6eb9b5..8fd7949 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -23,51 +23,13 @@
#include <config.h>
-#include <stdio.h>
-#include <stdlib.h>
#include <unistd.h>
-#include <string.h>
#include <assert.h>
-#include <signal.h>
-#include <sys/types.h>
-#include <sys/stat.h>
-#include <fcntl.h>
-#include <arpa/inet.h>
-#include <sys/wait.h>
-
-/* Windows socket compatibility functions. */
-#include <errno.h>
-#include <sys/socket.h>
-
-#ifndef HAVE_WINSOCK2_H /* Unix & Cygwin. */
-# include <sys/un.h>
-# include <net/if.h>
-# include <netinet/in.h>
-# include <netinet/tcp.h>
-#endif
-
-#ifdef HAVE_PWD_H
-# include <pwd.h>
-#endif
-
-#ifdef HAVE_PATHS_H
-# include <paths.h>
-#endif
-#include <rpc/types.h>
-#include <rpc/xdr.h>
-#include <gnutls/gnutls.h>
-#include <gnutls/x509.h>
-#include "gnutls_1_0_compat.h"
-#if HAVE_SASL
-# include <sasl/sasl.h>
-#endif
#include <libxml/uri.h>
-#include <netdb.h>
-
-#include <poll.h>
-
+#include "virnetclient.h"
+#include "virnetclientprogram.h"
#include "virterror_internal.h"
#include "logging.h"
#include "datatypes.h"
@@ -86,106 +48,24 @@
#define VIR_FROM_THIS VIR_FROM_REMOTE
-#ifdef WIN32
-# define pipe(fds) _pipe(fds,4096, _O_BINARY)
-#endif
-
-
static int inside_daemon = 0;
-struct remote_thread_call;
-
-
-enum {
- REMOTE_MODE_WAIT_TX,
- REMOTE_MODE_WAIT_RX,
- REMOTE_MODE_COMPLETE,
- REMOTE_MODE_ERROR,
-};
-
-struct remote_thread_call {
- int mode;
-
- /* Buffer for outgoing data packet
- * 4 byte length, followed by RPC message header+body */
- char buffer[4 + REMOTE_MESSAGE_MAX];
- unsigned int bufferLength;
- unsigned int bufferOffset;
-
- unsigned int serial;
- unsigned int proc_nr;
-
- virCond cond;
-
- int want_reply;
- xdrproc_t ret_filter;
- char *ret;
-
- remote_error err;
-
- struct remote_thread_call *next;
-};
+struct private_data {
+ virMutex lock;
-struct private_stream_data {
- unsigned int has_error : 1;
- remote_error err;
-
- unsigned int serial;
- unsigned int proc_nr;
-
- virStreamEventCallback cb;
- void *cbOpaque;
- virFreeCallback cbFree;
- int cbEvents;
- int cbTimer;
- int cbDispatch;
-
- /* XXX this is potentially unbounded if the client
- * app has domain events registered, since packets
- * may be read off wire, while app isn't ready to
- * recv them. Figure out how to address this some
- * time....
- */
- char *incoming;
- unsigned int incomingOffset;
- unsigned int incomingLength;
+ virNetClientPtr client;
+ virNetClientProgramPtr remoteProgram;
+ virNetClientProgramPtr qemuProgram;
- struct private_stream_data *next;
-};
+ int counter; /* Serial number for RPC */
-struct private_data {
- virMutex lock;
+ virNetTLSContextPtr tls;
- int sock; /* Socket. */
- int errfd; /* File handle connected to remote stderr */
int watch; /* File handle watch */
- pid_t pid; /* PID of tunnel process */
- int uses_tls; /* TLS enabled on socket? */
int is_secure; /* Secure if TLS or SASL or UNIX sockets */
- gnutls_session_t session; /* GnuTLS session (if uses_tls != 0). */
char *type; /* Cached return from remoteType. */
- int counter; /* Generates serial numbers for RPC. */
int localUses; /* Ref count for private data */
char *hostname; /* Original hostname */
- FILE *debugLog; /* Debug remote protocol */
-
-#if HAVE_SASL
- sasl_conn_t *saslconn; /* SASL context */
-
- const char *saslDecoded;
- unsigned int saslDecodedLength;
- unsigned int saslDecodedOffset;
-
- const char *saslEncoded;
- unsigned int saslEncodedLength;
- unsigned int saslEncodedOffset;
-#endif
-
- /* Buffer for incoming data packets
- * 4 byte length, followed by RPC message header+body */
- char buffer[4 + REMOTE_MESSAGE_MAX];
- unsigned int bufferLength;
- unsigned int bufferOffset;
/* The list of domain event callbacks */
virDomainEventCallbackListPtr callbackList;
@@ -196,15 +76,6 @@ struct private_data {
int eventFlushTimer;
/* Flag if we're in process of dispatching */
int domainEventDispatching;
-
- /* Self-pipe to wakeup threads waiting in poll() */
- int wakeupSendFD;
- int wakeupReadFD;
-
- /* List of threads currently waiting for dispatch */
- struct remote_thread_call *waitDispatch;
-
- struct private_stream_data *streams;
};
enum {
@@ -225,10 +96,6 @@ static void remoteDriverUnlock(struct private_data *driver)
virMutexUnlock(&driver->lock);
}
-static int remoteIO(virConnectPtr conn,
- struct private_data *priv,
- int flags,
- struct remote_thread_call *thiscall);
static int call (virConnectPtr conn, struct private_data *priv,
int flags, int proc_nr,
xdrproc_t args_filter, char *args,
@@ -272,10 +139,6 @@ void remoteDomainEventQueueFlush(int timer, void *opaque);
/* Helper functions for remoteOpen. */
static char *get_transport_from_scheme (char *scheme);
-/* GnuTLS functions used by remoteOpen. */
-static int initialize_gnutls(void);
-static gnutls_session_t negotiate_gnutls_on_connection (virConnectPtr conn, struct
private_data *priv, int no_verify);
-
#ifdef WITH_LIBVIRTD
static int
remoteStartup(int privileged ATTRIBUTE_UNUSED)
@@ -290,7 +153,7 @@ remoteStartup(int privileged ATTRIBUTE_UNUSED)
#ifndef WIN32
/**
- * remoteFindServerPath:
+ * remoteFindDaemonPath:
*
* Tries to find the path to the libvirtd binary.
*
@@ -317,36 +180,68 @@ remoteFindDaemonPath(void)
}
return NULL;
}
+#endif
-/**
- * qemuForkDaemon:
- *
- * Forks and try to launch the libvirtd daemon
- *
- * Returns 0 in case of success or -1 in case of detected error.
- */
-static int
-remoteForkDaemon(void)
-{
- const char *daemonPath = remoteFindDaemonPath();
- const char *const daemonargs[] = { daemonPath, "--timeout=30", NULL };
- pid_t pid;
-
- if (!daemonPath) {
- remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to find libvirtd binary"));
- return -1;
- }
-
- if (virExecDaemonize(daemonargs, NULL, NULL,
- &pid, -1, NULL, NULL,
- VIR_EXEC_CLEAR_CAPS,
- NULL, NULL, NULL) < 0)
- return -1;
- return 0;
-}
-#endif
+static void
+remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque);
+static void
+remoteDomainBuildEventReboot(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque);
+static void
+remoteDomainBuildEventRTCChange(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+static void
+remoteDomainBuildEventWatchdog(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+static void
+remoteDomainBuildEventIOError(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+static void
+remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+static void
+remoteDomainBuildEventGraphics(virNetClientProgramPtr prog,
+ virNetClientPtr client,
+ void *evdata, void *opaque);
+
+static virNetClientProgramEvent remoteDomainEvents[] = {
+ { REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE,
+ remoteDomainBuildEventRTCChange,
+ sizeof(remote_domain_event_rtc_change_msg),
+ (xdrproc_t)xdr_remote_domain_event_rtc_change_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_REBOOT,
+ remoteDomainBuildEventReboot,
+ sizeof(remote_domain_event_reboot_msg),
+ (xdrproc_t)xdr_remote_domain_event_reboot_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE,
+ remoteDomainBuildEventLifecycle,
+ sizeof(remote_domain_event_lifecycle_msg),
+ (xdrproc_t)xdr_remote_domain_event_lifecycle_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_WATCHDOG,
+ remoteDomainBuildEventWatchdog,
+ sizeof(remote_domain_event_watchdog_msg),
+ (xdrproc_t)xdr_remote_domain_event_watchdog_msg},
+ { REMOTE_PROC_DOMAIN_EVENT_IO_ERROR,
+ remoteDomainBuildEventIOError,
+ sizeof(remote_domain_event_io_error_msg),
+ (xdrproc_t)xdr_remote_domain_event_io_error_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON,
+ remoteDomainBuildEventIOErrorReason,
+ sizeof(remote_domain_event_io_error_reason_msg),
+ (xdrproc_t)xdr_remote_domain_event_io_error_reason_msg },
+ { REMOTE_PROC_DOMAIN_EVENT_GRAPHICS,
+ remoteDomainBuildEventGraphics,
+ sizeof(remote_domain_event_graphics_msg),
+ (xdrproc_t)xdr_remote_domain_event_graphics_address },
+};
enum virDrvOpenRemoteFlags {
VIR_DRV_OPEN_REMOTE_RO = (1 << 0),
@@ -379,7 +274,6 @@ doRemoteOpen (virConnectPtr conn,
int flags)
{
struct qparam_set *vars = NULL;
- int wakeupFD[2] = { -1, -1 };
char *transport_str = NULL;
enum {
trans_tls,
@@ -508,15 +402,10 @@ doRemoteOpen (virConnectPtr conn,
} else if (STRCASEEQ (var->name, "no_tty")) {
no_tty = atoi (var->value);
var->ignore = 1;
- } else if (STRCASEEQ (var->name, "debug")) {
- if (var->value &&
- STRCASEEQ (var->value, "stdout"))
- priv->debugLog = stdout;
- else
- priv->debugLog = stderr;
- } else
+ } else {
DEBUG("passing through variable '%s' ('%s') to
remote end",
var->name, var->value);
+ }
}
/* Construct the original name. */
@@ -579,89 +468,35 @@ doRemoteOpen (virConnectPtr conn,
goto failed;
}
+
+ VIR_DEBUG("Connecting with transport %d", transport);
/* Connect to the remote service. */
switch (transport) {
case trans_tls:
- if (initialize_gnutls() == -1) goto failed;
- priv->uses_tls = 1;
+ priv->tls = virNetTLSContextNewClient(LIBVIRT_CACERT,
+ LIBVIRT_CLIENTCERT,
+ LIBVIRT_CLIENTKEY,
+ no_verify ? false : true);
+ if (!priv->tls)
+ goto failed;
priv->is_secure = 1;
/*FALLTHROUGH*/
- case trans_tcp: {
- //
http://people.redhat.com/drepper/userapi-ipv6.html
- struct addrinfo *res, *r;
- struct addrinfo hints;
- int saved_errno = EINVAL;
- memset (&hints, 0, sizeof hints);
- hints.ai_socktype = SOCK_STREAM;
- hints.ai_flags = AI_ADDRCONFIG;
- int e = getaddrinfo (priv->hostname, port, &hints, &res);
- if (e != 0) {
- remoteError(VIR_ERR_SYSTEM_ERROR,
- _("unable to resolve hostname '%s': %s"),
- priv->hostname, gai_strerror (e));
+ case trans_tcp:
+ priv->client = virNetClientNewTCP(priv->hostname, port);
+ if (!priv->client)
goto failed;
- }
- /* Try to connect to each returned address in turn. */
- /* XXX This loop contains a subtle problem. In the case
- * where a host is accessible over IPv4 and IPv6, it will
- * try the IPv4 and IPv6 addresses in turn. However it
- * should be able to present different client certificates
- * (because the commonName field in a client cert contains
- * the client IP address, which is different for IPv4 and
- * IPv6). At the moment we only have a single client
- * certificate, and no way to specify what address family
- * that certificate belongs to.
- */
- for (r = res; r; r = r->ai_next) {
- int no_slow_start = 1;
-
- priv->sock = socket (r->ai_family, SOCK_STREAM, 0);
- if (priv->sock == -1) {
- saved_errno = errno;
- continue;
- }
-
- /* Disable Nagle - Dan Berrange. */
- setsockopt (priv->sock,
- IPPROTO_TCP, TCP_NODELAY, (void *)&no_slow_start,
- sizeof no_slow_start);
-
- if (connect (priv->sock, r->ai_addr, r->ai_addrlen) == -1) {
- saved_errno = errno;
- VIR_FORCE_CLOSE(priv->sock);
- continue;
- }
-
- if (priv->uses_tls) {
- priv->session =
- negotiate_gnutls_on_connection
- (conn, priv, no_verify);
- if (!priv->session) {
- VIR_FORCE_CLOSE(priv->sock);
- goto failed;
- }
- }
- goto tcp_connected;
+ if (priv->tls) {
+ VIR_DEBUG0("Starting TLS session");
+ if (virNetClientSetTLSSession(priv->client, priv->tls) < 0)
+ goto failed;
}
- freeaddrinfo (res);
- virReportSystemError(saved_errno,
- _("unable to connect to libvirtd at
'%s'"),
- priv->hostname);
- goto failed;
-
- tcp_connected:
- freeaddrinfo (res);
-
- // NB. All versioning is done by the RPC headers, so we don't
- // need to worry (at this point anyway) about versioning.
break;
- }
#ifndef WIN32
- case trans_unix: {
+ case trans_unix:
if (!sockname) {
if (flags & VIR_DRV_OPEN_REMOTE_USER) {
char *userdir = virGetUserDirectory(getuid());
@@ -676,153 +511,57 @@ doRemoteOpen (virConnectPtr conn,
VIR_FREE(userdir);
} else {
if (flags & VIR_DRV_OPEN_REMOTE_RO)
- sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET_RO);
+ sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO);
else
- sockname = strdup (LIBVIRTD_PRIV_UNIX_SOCKET);
+ sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET);
if (sockname == NULL)
goto out_of_memory;
}
+ VIR_DEBUG("Proceeding with sockname %s", sockname);
}
-# ifndef UNIX_PATH_MAX
-# define UNIX_PATH_MAX(addr) (sizeof (addr).sun_path)
-# endif
- struct sockaddr_un addr;
- int trials = 0;
-
- memset (&addr, 0, sizeof addr);
- addr.sun_family = AF_UNIX;
- if (virStrcpyStatic(addr.sun_path, sockname) == NULL) {
- remoteError(VIR_ERR_INTERNAL_ERROR,
- _("Socket %s too big for destination"), sockname);
- goto failed;
- }
- if (addr.sun_path[0] == '@')
- addr.sun_path[0] = '\0';
-
- autostart_retry:
- priv->is_secure = 1;
- priv->sock = socket (AF_UNIX, SOCK_STREAM, 0);
- if (priv->sock == -1) {
- virReportSystemError(errno, "%s",
- _("unable to create socket"));
- goto failed;
- }
- if (connect (priv->sock, (struct sockaddr *) &addr, sizeof addr) == -1) {
- /* We might have to autostart the daemon in some cases....
- * It takes a short while for the daemon to startup, hence we
- * have a number of retries, with a small sleep. This will
- * sometimes cause multiple daemons to be started - this is
- * ok because the duplicates will fail to bind to the socket
- * and immediately exit, leaving just one daemon.
- */
- if (errno == ECONNREFUSED &&
- flags & VIR_DRV_OPEN_REMOTE_AUTOSTART &&
- trials < 20) {
- VIR_FORCE_CLOSE(priv->sock);
- if (trials > 0 ||
- remoteForkDaemon() == 0) {
- trials++;
- usleep(1000 * 100 * trials);
- goto autostart_retry;
- }
- }
- virReportSystemError(errno,
- _("unable to connect to '%s', libvirtd may need to be
started"),
- sockname);
+ if (!(priv->client = virNetClientNewUNIX(sockname,
+ flags &
VIR_DRV_OPEN_REMOTE_AUTOSTART,
+ remoteFindDaemonPath())))
goto failed;
- }
break;
- }
-
- case trans_ssh: {
- int j, nr_args = 6;
-
- if (username) nr_args += 2; /* For -l username */
- if (no_tty) nr_args += 5; /* For -T -o BatchMode=yes -e none */
- if (port) nr_args += 2; /* For -p port */
+ case trans_ssh:
command = command ? command : strdup ("ssh");
if (command == NULL)
goto out_of_memory;
- // Generate the final command argv[] array.
- // ssh [-p $port] [-l $username] $hostname $netcat -U $sockname [NULL]
- if (VIR_ALLOC_N(cmd_argv, nr_args) < 0)
- goto out_of_memory;
-
- j = 0;
- cmd_argv[j++] = strdup (command);
- if (port) {
- cmd_argv[j++] = strdup ("-p");
- cmd_argv[j++] = strdup (port);
- }
- if (username) {
- cmd_argv[j++] = strdup ("-l");
- cmd_argv[j++] = strdup (username);
- }
- if (no_tty) {
- cmd_argv[j++] = strdup ("-T");
- cmd_argv[j++] = strdup ("-o");
- cmd_argv[j++] = strdup ("BatchMode=yes");
- cmd_argv[j++] = strdup ("-e");
- cmd_argv[j++] = strdup ("none");
- }
- cmd_argv[j++] = strdup (priv->hostname);
- cmd_argv[j++] = strdup (netcat ? netcat : "nc");
- cmd_argv[j++] = strdup ("-U");
- cmd_argv[j++] = strdup (sockname ? sockname :
- (flags & VIR_CONNECT_RO
- ? LIBVIRTD_PRIV_UNIX_SOCKET_RO
- : LIBVIRTD_PRIV_UNIX_SOCKET));
- cmd_argv[j++] = 0;
- assert (j == nr_args);
- for (j = 0; j < (nr_args-1); j++)
- if (cmd_argv[j] == NULL)
+ if (!sockname) {
+ if (flags & VIR_DRV_OPEN_REMOTE_RO)
+ sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET_RO);
+ else
+ sockname = strdup(LIBVIRTD_PRIV_UNIX_SOCKET);
+ if (sockname == NULL)
goto out_of_memory;
-
- priv->is_secure = 1;
- }
-
- /*FALLTHROUGH*/
- case trans_ext: {
- pid_t pid;
- int sv[2];
- int errfd[2];
-
- /* Fork off the external process. Use socketpair to create a private
- * (unnamed) Unix domain socket to the child process so we don't have
- * to faff around with two file descriptors (a la 'pipe(2)').
- */
- if (socketpair (PF_UNIX, SOCK_STREAM, 0, sv) == -1) {
- virReportSystemError(errno, "%s",
- _("unable to create socket pair"));
- goto failed;
}
- if (pipe(errfd) == -1) {
- virReportSystemError(errno, "%s",
- _("unable to create socket pair"));
+ if (!(priv->client = virNetClientNewSSH(priv->hostname,
+ port,
+ command,
+ username,
+ no_tty,
+ netcat ? netcat : "nc",
+ sockname)))
goto failed;
- }
- if (virExec((const char**)cmd_argv, NULL, NULL,
- &pid, sv[1], &(sv[1]), &(errfd[1]),
- VIR_EXEC_CLEAR_CAPS) < 0)
- goto failed;
+ priv->is_secure = 1;
+ break;
- /* Parent continues here. */
- VIR_FORCE_CLOSE(sv[1]);
- VIR_FORCE_CLOSE(errfd[1]);
- priv->sock = sv[0];
- priv->errfd = errfd[0];
- priv->pid = pid;
+ case trans_ext:
+ if (!(priv->client = virNetClientNewCommand((const char **)cmd_argv, NULL)))
+ goto failed;
/* Do not set 'is_secure' flag since we can't guarentee
* an external program is secure, and this flag must be
* pessimistic */
- }
+ break;
+
#else /* WIN32 */
case trans_unix:
@@ -834,36 +573,32 @@ doRemoteOpen (virConnectPtr conn,
goto failed;
#endif /* WIN32 */
-
} /* switch (transport) */
- if (virSetNonBlock(priv->sock) < 0) {
- virReportSystemError(errno, "%s",
- _("unable to make socket non-blocking"));
- goto failed;
- }
-
- if ((priv->errfd != -1) && virSetNonBlock(priv->errfd) < 0) {
- virReportSystemError(errno, "%s",
- _("unable to make socket non-blocking"));
+ if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM,
+ REMOTE_PROTOCOL_VERSION,
+ remoteDomainEvents,
+
ARRAY_CARDINALITY(remoteDomainEvents),
+ conn,
+ NULL)))
goto failed;
- }
-
- if (pipe(wakeupFD) < 0) {
- virReportSystemError(errno, "%s",
- _("unable to make pipe"));
+ if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM,
+ QEMU_PROTOCOL_VERSION,
+ NULL,
+ 0,
+ NULL,
+ NULL)))
goto failed;
- }
- priv->wakeupReadFD = wakeupFD[0];
- priv->wakeupSendFD = wakeupFD[1];
/* Try and authenticate with server */
+ VIR_DEBUG0("Trying authentication");
if (remoteAuthenticate(conn, priv, 1, auth, authtype) == -1)
goto failed;
/* Finally we can call the remote side's open function. */
remote_open_args args = { &name, flags };
+ VIR_DEBUG("Trying to open URI %s", name);
if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN,
(xdrproc_t) xdr_remote_open_args, (char *) &args,
(xdrproc_t) xdr_void, (char *) NULL) == -1)
@@ -874,6 +609,7 @@ doRemoteOpen (virConnectPtr conn,
remote_get_uri_ret uriret;
int urierr;
+ VIR_DEBUG0("Trying to query remote URI");
memset (&uriret, 0, sizeof uriret);
urierr = call (conn, priv,
REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC,
@@ -902,36 +638,23 @@ doRemoteOpen (virConnectPtr conn,
}
}
- if(VIR_ALLOC(priv->callbackList)<0) {
+ if (VIR_ALLOC(priv->callbackList)<0) {
virReportOOMError();
goto failed;
}
- if(VIR_ALLOC(priv->domainEvents)<0) {
+ if (VIR_ALLOC(priv->domainEvents)<0) {
virReportOOMError();
goto failed;
}
- DEBUG0("Adding Handler for remote events");
- /* Set up a callback to listen on the socket data */
- if ((priv->watch = virEventAddHandle(priv->sock,
- VIR_EVENT_HANDLE_READABLE,
- remoteDomainEventFired,
- conn, NULL)) < 0) {
- DEBUG0("virEventAddHandle failed: No addHandleImpl defined."
- " continuing without events.");
- } else {
-
- DEBUG0("Adding Timeout for remote event queue flushing");
- if ( (priv->eventFlushTimer = virEventAddTimeout(-1,
- remoteDomainEventQueueFlush,
- conn, NULL)) < 0) {
- DEBUG0("virEventAddTimeout failed: No addTimeoutImpl defined. "
- "continuing without events.");
- virEventRemoveHandle(priv->watch);
- priv->watch = -1;
- }
+ DEBUG0("Adding Timeout for remote event queue flushing");
+ if ((priv->eventFlushTimer = virEventAddTimeout(-1,
+ remoteDomainEventQueueFlush,
+ conn, NULL)) < 0) {
+ DEBUG0("Failed to add timer for dispatching events, disabling
events");
}
+
/* Successful. */
retcode = VIR_DRV_OPEN_SUCCESS;
@@ -961,30 +684,8 @@ doRemoteOpen (virConnectPtr conn,
free_qparam_set (vars);
failed:
- /* Close the socket if we failed. */
- VIR_FORCE_CLOSE(priv->errfd);
-
- if (priv->sock >= 0) {
- if (priv->uses_tls && priv->session) {
- gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
- gnutls_deinit (priv->session);
- }
- VIR_FORCE_CLOSE(priv->sock);
-#ifndef WIN32
- if (priv->pid > 0) {
- pid_t reap;
- do {
-retry:
- reap = waitpid(priv->pid, NULL, 0);
- if (reap == -1 && errno == EINTR)
- goto retry;
- } while (reap != -1 && reap != priv->pid);
- }
-#endif
- }
-
- VIR_FORCE_CLOSE(wakeupFD[0]);
- VIR_FORCE_CLOSE(wakeupFD[1]);
+ virNetClientFree(priv->client);
+ priv->client = NULL;
VIR_FREE(priv->hostname);
goto cleanup;
@@ -1008,8 +709,6 @@ remoteAllocPrivateData(void)
remoteDriverLock(priv);
priv->localUses = 1;
priv->watch = -1;
- priv->sock = -1;
- priv->errfd = -1;
return priv;
}
@@ -1121,435 +820,98 @@ get_transport_from_scheme (char *scheme)
return p ? p+1 : 0;
}
-/* GnuTLS functions used by remoteOpen. */
-static gnutls_certificate_credentials_t x509_cred;
-
-
-static int
-check_cert_file(const char *type, const char *file)
-{
- struct stat sb;
- if (stat(file, &sb) < 0) {
- virReportSystemError(errno,
- _("Cannot access %s '%s'"),
- type, file);
- return -1;
- }
- return 0;
-}
-
+/*----------------------------------------------------------------------*/
-static void remote_debug_gnutls_log(int level, const char* str) {
- DEBUG("%d %s", level, str);
-}
static int
-initialize_gnutls(void)
+doRemoteClose (virConnectPtr conn, struct private_data *priv)
{
- static int initialized = 0;
- int err;
- char *gnutlsdebug;
-
- if (initialized) return 0;
-
- gnutls_global_init ();
-
- if ((gnutlsdebug = getenv("LIBVIRT_GNUTLS_DEBUG")) != NULL) {
- int val;
- if (virStrToLong_i(gnutlsdebug, NULL, 10, &val) < 0)
- val = 10;
- gnutls_global_set_log_level(val);
- gnutls_global_set_log_function(remote_debug_gnutls_log);
- }
-
- /* X509 stuff */
- err = gnutls_certificate_allocate_credentials (&x509_cred);
- if (err) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to allocate TLS credentials: %s"),
- gnutls_strerror (err));
- return -1;
+ if (priv->eventFlushTimer >= 0) {
+ /* Remove timeout */
+ virEventRemoveTimeout(priv->eventFlushTimer);
+ /* Remove handle for remote events */
+ virEventRemoveHandle(priv->watch);
+ priv->watch = -1;
}
-
- if (check_cert_file("CA certificate", LIBVIRT_CACERT) < 0)
- return -1;
- if (check_cert_file("client key", LIBVIRT_CLIENTKEY) < 0)
- return -1;
- if (check_cert_file("client certificate", LIBVIRT_CLIENTCERT) < 0)
+ if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
+ (xdrproc_t) xdr_void, (char *) NULL,
+ (xdrproc_t) xdr_void, (char *) NULL) == -1)
return -1;
- /* Set the trusted CA cert. */
- DEBUG("loading CA file %s", LIBVIRT_CACERT);
- err =
- gnutls_certificate_set_x509_trust_file (x509_cred, LIBVIRT_CACERT,
- GNUTLS_X509_FMT_PEM);
- if (err < 0) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to load CA certificate: %s"),
- gnutls_strerror (err));
- return -1;
- }
+ virNetTLSContextFree(priv->tls);
+ priv->tls = NULL;
+ virNetClientFree(priv->client);
+ priv->client = NULL;
+ virNetClientProgramFree(priv->remoteProgram);
+ virNetClientProgramFree(priv->qemuProgram);
+ priv->remoteProgram = priv->qemuProgram = NULL;
- /* Set the client certificate and private key. */
- DEBUG("loading client cert and key from files %s and %s",
- LIBVIRT_CLIENTCERT, LIBVIRT_CLIENTKEY);
- err =
- gnutls_certificate_set_x509_key_file (x509_cred,
- LIBVIRT_CLIENTCERT,
- LIBVIRT_CLIENTKEY,
- GNUTLS_X509_FMT_PEM);
- if (err < 0) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to load private key/certificate: %s"),
- gnutls_strerror (err));
- return -1;
- }
+ /* Free hostname copy */
+ VIR_FREE(priv->hostname);
- initialized = 1;
- return 0;
-}
+ /* See comment for remoteType. */
+ VIR_FREE(priv->type);
-static int verify_certificate (virConnectPtr conn, struct private_data *priv,
gnutls_session_t session);
+ /* Free callback list */
+ virDomainEventCallbackListFree(priv->callbackList);
-#if HAVE_WINSOCK2_H
-static ssize_t
-custom_gnutls_push(void *s, const void *buf, size_t len)
-{
- return send((size_t)s, buf, len, 0);
-}
+ /* Free queued events */
+ virDomainEventQueueFree(priv->domainEvents);
-static ssize_t
-custom_gnutls_pull(void *s, void *buf, size_t len)
-{
- return recv((size_t)s, buf, len, 0);
+ return 0;
}
-#endif
-static gnutls_session_t
-negotiate_gnutls_on_connection (virConnectPtr conn,
- struct private_data *priv,
- int no_verify)
+static int
+remoteClose (virConnectPtr conn)
{
- const int cert_type_priority[3] = {
- GNUTLS_CRT_X509,
- GNUTLS_CRT_OPENPGP,
- 0
- };
- int err;
- gnutls_session_t session;
-
- /* Initialize TLS session
- */
- err = gnutls_init (&session, GNUTLS_CLIENT);
- if (err) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to initialize TLS client: %s"),
- gnutls_strerror (err));
- return NULL;
- }
+ int ret = 0;
+ struct private_data *priv = conn->privateData;
- /* Use default priorities */
- err = gnutls_set_default_priority (session);
- if (err) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to set TLS algorithm priority: %s"),
- gnutls_strerror (err));
- return NULL;
- }
- err =
- gnutls_certificate_type_set_priority (session,
- cert_type_priority);
- if (err) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to set certificate priority: %s"),
- gnutls_strerror (err));
- return NULL;
+ remoteDriverLock(priv);
+ priv->localUses--;
+ if (!priv->localUses) {
+ ret = doRemoteClose(conn, priv);
+ conn->privateData = NULL;
+ remoteDriverUnlock(priv);
+ virMutexDestroy(&priv->lock);
+ VIR_FREE (priv);
}
+ if (priv)
+ remoteDriverUnlock(priv);
- /* put the x509 credentials to the current session
- */
- err = gnutls_credentials_set (session, GNUTLS_CRD_CERTIFICATE, x509_cred);
- if (err) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to set session credentials: %s"),
- gnutls_strerror (err));
- return NULL;
- }
+ return ret;
+}
- gnutls_transport_set_ptr (session,
- (gnutls_transport_ptr_t) (long) priv->sock);
+static int
+remoteSupportsFeature (virConnectPtr conn, int feature)
+{
+ int rv = -1;
+ remote_supports_feature_args args;
+ remote_supports_feature_ret ret;
+ struct private_data *priv = conn->privateData;
-#if HAVE_WINSOCK2_H
- /* Make sure GnuTLS uses gnulib's replacment functions for send() and
- * recv() on Windows */
- gnutls_transport_set_push_function(session, custom_gnutls_push);
- gnutls_transport_set_pull_function(session, custom_gnutls_pull);
-#endif
+ remoteDriverLock(priv);
- /* Perform the TLS handshake. */
- again:
- err = gnutls_handshake (session);
- if (err < 0) {
- if (err == GNUTLS_E_AGAIN || err == GNUTLS_E_INTERRUPTED)
- goto again;
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to complete TLS handshake: %s"),
- gnutls_strerror (err));
- return NULL;
+ /* VIR_DRV_FEATURE_REMOTE* features are handled directly. */
+ if (feature == VIR_DRV_FEATURE_REMOTE) {
+ rv = 1;
+ goto done;
}
- /* Verify certificate. */
- if (verify_certificate (conn, priv, session) == -1) {
- DEBUG0("failed to verify peer's certificate");
- if (!no_verify) return NULL;
- }
+ args.feature = feature;
- /* At this point, the server is verifying _our_ certificate, IP address,
- * etc. If we make the grade, it will send us a '\1' byte.
- */
- char buf[1];
- int len;
- again_2:
- len = gnutls_record_recv (session, buf, 1);
- if (len < 0 && len != GNUTLS_E_UNEXPECTED_PACKET_LENGTH) {
- if (len == GNUTLS_E_AGAIN || len == GNUTLS_E_INTERRUPTED)
- goto again_2;
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to complete TLS initialization: %s"),
- gnutls_strerror (len));
- return NULL;
- }
- if (len != 1 || buf[0] != '\1') {
- remoteError(VIR_ERR_RPC, "%s",
- _("server verification (of our certificate or IP "
- "address) failed"));
- return NULL;
- }
+ memset (&ret, 0, sizeof ret);
+ if (call (conn, priv, 0, REMOTE_PROC_SUPPORTS_FEATURE,
+ (xdrproc_t) xdr_remote_supports_feature_args, (char *) &args,
+ (xdrproc_t) xdr_remote_supports_feature_ret, (char *) &ret) == -1)
+ goto done;
-#if 0
- /* Print session info. */
- print_info (session);
-#endif
+ rv = ret.supported;
- return session;
-}
-
-static int
-verify_certificate (virConnectPtr conn ATTRIBUTE_UNUSED,
- struct private_data *priv,
- gnutls_session_t session)
-{
- int ret;
- unsigned int status;
- const gnutls_datum_t *certs;
- unsigned int nCerts, i;
- time_t now;
-
- if ((ret = gnutls_certificate_verify_peers2 (session, &status)) < 0) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to verify server certificate: %s"),
- gnutls_strerror (ret));
- return -1;
- }
-
- if ((now = time(NULL)) == ((time_t)-1)) {
- virReportSystemError(errno, "%s",
- _("cannot get current time"));
- return -1;
- }
-
- if (status != 0) {
- const char *reason = _("Invalid certificate");
-
- if (status & GNUTLS_CERT_INVALID)
- reason = _("The certificate is not trusted.");
-
- if (status & GNUTLS_CERT_SIGNER_NOT_FOUND)
- reason = _("The certificate hasn't got a known issuer.");
-
- if (status & GNUTLS_CERT_REVOKED)
- reason = _("The certificate has been revoked.");
-
-#ifndef GNUTLS_1_0_COMPAT
- if (status & GNUTLS_CERT_INSECURE_ALGORITHM)
- reason = _("The certificate uses an insecure algorithm");
-#endif
-
- remoteError(VIR_ERR_RPC,
- _("server certificate failed validation: %s"),
- reason);
- return -1;
- }
-
- if (gnutls_certificate_type_get(session) != GNUTLS_CRT_X509) {
- remoteError(VIR_ERR_RPC, "%s",_("Certificate type is not
X.509"));
- return -1;
- }
-
- if (!(certs = gnutls_certificate_get_peers(session, &nCerts))) {
- remoteError(VIR_ERR_RPC, "%s",_("gnutls_certificate_get_peers
failed"));
- return -1;
- }
-
- for (i = 0 ; i < nCerts ; i++) {
- gnutls_x509_crt_t cert;
-
- ret = gnutls_x509_crt_init (&cert);
- if (ret < 0) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to initialize certificate: %s"),
- gnutls_strerror (ret));
- return -1;
- }
-
- ret = gnutls_x509_crt_import (cert, &certs[i], GNUTLS_X509_FMT_DER);
- if (ret < 0) {
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("unable to import certificate: %s"),
- gnutls_strerror (ret));
- gnutls_x509_crt_deinit (cert);
- return -1;
- }
-
- if (gnutls_x509_crt_get_expiration_time (cert) < now) {
- remoteError(VIR_ERR_RPC, "%s", _("The certificate has
expired"));
- gnutls_x509_crt_deinit (cert);
- return -1;
- }
-
- if (gnutls_x509_crt_get_activation_time (cert) > now) {
- remoteError(VIR_ERR_RPC, "%s",
- _("The certificate is not yet activated"));
- gnutls_x509_crt_deinit (cert);
- return -1;
- }
-
- if (i == 0) {
- if (!gnutls_x509_crt_check_hostname (cert, priv->hostname)) {
- remoteError(VIR_ERR_RPC,
- _("Certificate's owner does not match the hostname
(%s)"),
- priv->hostname);
- gnutls_x509_crt_deinit (cert);
- return -1;
- }
- }
- }
-
- return 0;
-}
-
-/*----------------------------------------------------------------------*/
-
-
-static int
-doRemoteClose (virConnectPtr conn, struct private_data *priv)
-{
- if (priv->eventFlushTimer >= 0) {
- /* Remove timeout */
- virEventRemoveTimeout(priv->eventFlushTimer);
- /* Remove handle for remote events */
- virEventRemoveHandle(priv->watch);
- priv->watch = -1;
- }
-
- if (call (conn, priv, 0, REMOTE_PROC_CLOSE,
- (xdrproc_t) xdr_void, (char *) NULL,
- (xdrproc_t) xdr_void, (char *) NULL) == -1)
- return -1;
-
- /* Close socket. */
- if (priv->uses_tls && priv->session) {
- gnutls_bye (priv->session, GNUTLS_SHUT_RDWR);
- gnutls_deinit (priv->session);
- }
-#if HAVE_SASL
- if (priv->saslconn)
- sasl_dispose (&priv->saslconn);
-#endif
- VIR_FORCE_CLOSE(priv->sock);
- VIR_FORCE_CLOSE(priv->errfd);
-
-#ifndef WIN32
- if (priv->pid > 0) {
- pid_t reap;
- do {
-retry:
- reap = waitpid(priv->pid, NULL, 0);
- if (reap == -1 && errno == EINTR)
- goto retry;
- } while (reap != -1 && reap != priv->pid);
- }
-#endif
- VIR_FORCE_CLOSE(priv->wakeupReadFD);
- VIR_FORCE_CLOSE(priv->wakeupSendFD);
-
-
- /* Free hostname copy */
- VIR_FREE(priv->hostname);
-
- /* See comment for remoteType. */
- VIR_FREE(priv->type);
-
- /* Free callback list */
- virDomainEventCallbackListFree(priv->callbackList);
-
- /* Free queued events */
- virDomainEventQueueFree(priv->domainEvents);
-
- return 0;
-}
-
-static int
-remoteClose (virConnectPtr conn)
-{
- int ret = 0;
- struct private_data *priv = conn->privateData;
-
- remoteDriverLock(priv);
- priv->localUses--;
- if (!priv->localUses) {
- ret = doRemoteClose(conn, priv);
- conn->privateData = NULL;
- remoteDriverUnlock(priv);
- virMutexDestroy(&priv->lock);
- VIR_FREE (priv);
- }
- if (priv)
- remoteDriverUnlock(priv);
-
- return ret;
-}
-
-static int
-remoteSupportsFeature (virConnectPtr conn, int feature)
-{
- int rv = -1;
- remote_supports_feature_args args;
- remote_supports_feature_ret ret;
- struct private_data *priv = conn->privateData;
-
- remoteDriverLock(priv);
-
- /* VIR_DRV_FEATURE_REMOTE* features are handled directly. */
- if (feature == VIR_DRV_FEATURE_REMOTE) {
- rv = 1;
- goto done;
- }
-
- args.feature = feature;
-
- memset (&ret, 0, sizeof ret);
- if (call (conn, priv, 0, REMOTE_PROC_SUPPORTS_FEATURE,
- (xdrproc_t) xdr_remote_supports_feature_args, (char *) &args,
- (xdrproc_t) xdr_remote_supports_feature_ret, (char *) &ret) == -1)
- goto done;
-
- rv = ret.supported;
-
-done:
- remoteDriverUnlock(priv);
- return rv;
+done:
+ remoteDriverUnlock(priv);
+ return rv;
}
/* Unfortunately this function is defined to return a static string.
@@ -1701,13 +1063,8 @@ static int remoteIsEncrypted(virConnectPtr conn)
(xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1)
goto done;
- if (priv->uses_tls)
+ if (virNetClientIsEncrypted(priv->client))
encrypted = 1;
-#if HAVE_SASL
- else if (priv->saslconn)
- encrypted = 1;
-#endif
-
/* We claim to be encrypted, if the remote driver
* transport itself is encrypted, and the remote
@@ -7103,8 +6460,6 @@ static int
remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open,
virConnectAuthPtr auth, const char *wantmech)
{
- sasl_conn_t *saslconn = NULL;
- sasl_security_properties_t secprops;
remote_auth_sasl_init_ret iret;
remote_auth_sasl_start_args sargs;
remote_auth_sasl_start_ret sret;
@@ -7112,49 +6467,19 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
remote_auth_sasl_step_ret pret;
const char *clientout;
char *serverin = NULL;
- unsigned int clientoutlen, serverinlen;
+ size_t clientoutlen, serverinlen;
const char *mech;
int err, complete;
- virSocketAddr sa;
- char *localAddr = NULL, *remoteAddr = NULL;
- const void *val;
- sasl_ssf_t ssf;
+ int ssf;
sasl_callback_t *saslcb = NULL;
sasl_interact_t *interact = NULL;
virConnectCredentialPtr cred = NULL;
int ncred = 0;
int ret = -1;
const char *mechlist;
+ virNetClientSaslContextPtr sasl;
DEBUG0("Client initialize SASL authentication");
- /* Sets up the SASL library as a whole */
- err = sasl_client_init(NULL);
- if (err != SASL_OK) {
- remoteError(VIR_ERR_AUTH_FAILED,
- _("failed to initialize SASL library: %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
- goto cleanup;
- }
-
- /* Get local address in form IPADDR:PORT */
- sa.len = sizeof(sa.data.stor);
- if (getsockname(priv->sock, &sa.data.sa, &sa.len) < 0) {
- virReportSystemError(errno, "%s",
- _("failed to get sock address"));
- goto cleanup;
- }
- if ((localAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
- goto cleanup;
-
- /* Get remote address in form IPADDR:PORT */
- sa.len = sizeof(sa.data.stor);
- if (getpeername(priv->sock, &sa.data.sa, &sa.len) < 0) {
- virReportSystemError(errno, "%s",
- _("failed to get peer address"));
- goto cleanup;
- }
- if ((remoteAddr = virSocketFormatAddrFull(&sa, true, ";")) == NULL)
- goto cleanup;
if (auth) {
if ((saslcb = remoteAuthMakeCallbacks(auth->credtype, auth->ncredtype)) ==
NULL)
@@ -7164,59 +6489,32 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
}
/* Setup a handle for being a client */
- err = sasl_client_new("libvirt",
- priv->hostname,
- localAddr,
- remoteAddr,
- saslcb,
- SASL_SUCCESS_DATA,
- &saslconn);
-
- if (err != SASL_OK) {
- remoteError(VIR_ERR_AUTH_FAILED,
- _("Failed to create SASL client context: %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
+ if (!(sasl = virNetClientSaslContextNew("libvirt",
+ priv->hostname,
+
virNetClientLocalAddrString(priv->client),
+
virNetClientRemoteAddrString(priv->client),
+ saslcb)))
goto cleanup;
- }
/* Initialize some connection props we care about */
- if (priv->uses_tls) {
- gnutls_cipher_algorithm_t cipher;
-
- cipher = gnutls_cipher_get(priv->session);
- if (!(ssf = (sasl_ssf_t)gnutls_cipher_get_key_size(cipher))) {
- remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("invalid cipher size for TLS session"));
+ if (priv->tls) {
+ if ((ssf = virNetClientGetTLSKeySize(priv->client)) < 0)
goto cleanup;
- }
+
ssf *= 8; /* key size is bytes, sasl wants bits */
DEBUG("Setting external SSF %d", ssf);
- err = sasl_setprop(saslconn, SASL_SSF_EXTERNAL, &ssf);
- if (err != SASL_OK) {
- remoteError(VIR_ERR_INTERNAL_ERROR,
- _("cannot set external SSF %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
+ if (virNetClientSaslContextExtKeySize(sasl, ssf) < 0)
goto cleanup;
- }
}
- memset (&secprops, 0, sizeof secprops);
/* If we've got a secure channel (TLS or UNIX sock), we don't care about SSF
*/
- secprops.min_ssf = priv->is_secure ? 0 : 56; /* Equiv to DES supported by all
Kerberos */
- secprops.max_ssf = priv->is_secure ? 0 : 100000; /* Very strong ! AES == 256 */
- secprops.maxbufsize = 100000;
/* If we're not secure, then forbid any anonymous or trivially crackable auth */
- secprops.security_flags = priv->is_secure ? 0 :
- SASL_SEC_NOANONYMOUS | SASL_SEC_NOPLAINTEXT;
-
- err = sasl_setprop(saslconn, SASL_SEC_PROPS, &secprops);
- if (err != SASL_OK) {
- remoteError(VIR_ERR_INTERNAL_ERROR,
- _("cannot set security props %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
+ if (virNetClientSaslContextSecProps(sasl,
+ priv->is_secure ? 0 : 56, /* Equiv to DES
supported by all Kerberos */
+ priv->is_secure ? 0 : 100000, /* Very strong !
AES == 256 */
+ priv->is_secure ? true : false) < 0)
goto cleanup;
- }
/* First call is to inquire about supported mechanisms in the server */
memset (&iret, 0, sizeof iret);
@@ -7240,22 +6538,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
restart:
/* Start the auth negotiation on the client end first */
DEBUG("Client start negotiation mechlist '%s'", mechlist);
- err = sasl_client_start(saslconn,
- mechlist,
- &interact,
- &clientout,
- &clientoutlen,
- &mech);
- if (err != SASL_OK && err != SASL_CONTINUE && err != SASL_INTERACT)
{
- remoteError(VIR_ERR_AUTH_FAILED,
- _("Failed to start SASL negotiation: %d (%s)"),
- err, sasl_errdetail(saslconn));
- VIR_FREE(iret.mechlist);
+ if ((err = virNetClientSaslContextStart(sasl,
+ mechlist,
+ &interact,
+ &clientout,
+ &clientoutlen,
+ &mech)) < 0)
goto cleanup;
- }
/* Need to gather some credentials from the client */
- if (err == SASL_INTERACT) {
+ if (err == VIR_NET_CLIENT_SASL_INTERACT) {
const char *msg;
if (cred) {
remoteAuthFreeCredentials(cred, ncred);
@@ -7285,7 +6577,7 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
if (clientoutlen > REMOTE_AUTH_SASL_DATA_MAX) {
remoteError(VIR_ERR_AUTH_FAILED,
_("SASL negotiation data too long: %d bytes"),
- clientoutlen);
+ (int)clientoutlen);
goto cleanup;
}
/* NB, distinction of NULL vs "" is *critical* in SASL */
@@ -7294,7 +6586,8 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
sargs.data.data_val = (char*)clientout;
sargs.data.data_len = clientoutlen;
sargs.mech = (char*)mech;
- DEBUG("Server start negotiation with mech %s. Data %d bytes %p", mech,
clientoutlen, clientout);
+ DEBUG("Server start negotiation with mech %s. Data %d bytes %p",
+ mech, (int)clientoutlen, clientout);
/* Now send the initial auth data to the server */
memset (&sret, 0, sizeof sret);
@@ -7308,27 +6601,23 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
serverin = sret.nil ? NULL : sret.data.data_val;
serverinlen = sret.data.data_len;
DEBUG("Client step result complete: %d. Data %d bytes %p",
- complete, serverinlen, serverin);
+ complete, (int)serverinlen, serverin);
/* Loop-the-loop...
* Even if the server has completed, the client must *always* do at least one step
* in this loop to verify the server isn't lying about something. Mutual auth */
for (;;) {
restep:
- err = sasl_client_step(saslconn,
- serverin,
- serverinlen,
- &interact,
- &clientout,
- &clientoutlen);
- if (err != SASL_OK && err != SASL_CONTINUE && err !=
SASL_INTERACT) {
- remoteError(VIR_ERR_AUTH_FAILED,
- _("Failed SASL step: %d (%s)"),
- err, sasl_errdetail(saslconn));
+ if ((err = virNetClientSaslContextStep(sasl,
+ serverin,
+ serverinlen,
+ &interact,
+ &clientout,
+ &clientoutlen)) < 0)
goto cleanup;
- }
+
/* Need to gather some credentials from the client */
- if (err == SASL_INTERACT) {
+ if (err == VIR_NET_CLIENT_SASL_INTERACT) {
const char *msg;
if (cred) {
remoteAuthFreeCredentials(cred, ncred);
@@ -7354,10 +6643,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
}
VIR_FREE(serverin);
- DEBUG("Client step result %d. Data %d bytes %p", err, clientoutlen,
clientout);
+ DEBUG("Client step result %d. Data %d bytes %p",
+ err, (int)clientoutlen, clientout);
/* Previous server call showed completion & we're now locally complete
too */
- if (complete && err == SASL_OK)
+ if (complete && err == VIR_NET_CLIENT_SASL_COMPLETE)
break;
/* Not done, prepare to talk with the server for another iteration */
@@ -7366,7 +6656,8 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
pargs.nil = clientout ? 0 : 1;
pargs.data.data_val = (char*)clientout;
pargs.data.data_len = clientoutlen;
- DEBUG("Server step with %d bytes %p", clientoutlen, clientout);
+ DEBUG("Server step with %d bytes %p",
+ (int)clientoutlen, clientout);
memset (&pret, 0, sizeof pret);
if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_STEP,
@@ -7380,10 +6671,10 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
serverinlen = pret.data.data_len;
DEBUG("Client step result complete: %d. Data %d bytes %p",
- complete, serverinlen, serverin);
+ complete, (int)serverinlen, serverin);
/* This server call shows complete, and earlier client step was OK */
- if (complete && err == SASL_OK) {
+ if (complete && err == VIR_NET_CLIENT_SASL_COMPLETE) {
VIR_FREE(serverin);
break;
}
@@ -7391,14 +6682,9 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
/* Check for suitable SSF if not already secure (TLS or UNIX sock) */
if (!priv->is_secure) {
- err = sasl_getprop(saslconn, SASL_SSF, &val);
- if (err != SASL_OK) {
- remoteError(VIR_ERR_AUTH_FAILED,
- _("cannot query SASL ssf on connection %d (%s)"),
- err, sasl_errstring(err, NULL, NULL));
+ if ((ssf = virNetClientSaslContextGetKeySize(sasl)) < 0)
goto cleanup;
- }
- ssf = *(const int *)val;
+
DEBUG("SASL SSF value %d", ssf);
if (ssf < 56) { /* 56 == DES level, good for Kerberos */
remoteError(VIR_ERR_AUTH_FAILED,
@@ -7409,18 +6695,15 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int
in_open,
}
DEBUG0("SASL authentication complete");
- priv->saslconn = saslconn;
+ virNetClientSetSASLContext(priv->client, sasl);
ret = 0;
cleanup:
- VIR_FREE(localAddr);
- VIR_FREE(remoteAddr);
VIR_FREE(serverin);
VIR_FREE(saslcb);
remoteAuthFreeCredentials(cred, ncred);
- if (ret != 0 && saslconn)
- sasl_dispose(&saslconn);
+ virNetClientSaslContextFree(sasl);
return ret;
}
@@ -7573,184 +6856,187 @@ done:
return rv;
}
+
+static int remoteDomainEventQueuePush(struct private_data *priv,
+ virDomainEventPtr event)
+{
+ int ret = -1;
+ remoteDriverLock(priv);
+
+ if (virDomainEventQueuePush(priv->domainEvents,
+ event) < 0) {
+ DEBUG0("Error adding event to queue");
+ goto cleanup;
+ }
+
+ ret = 0;
+ virEventUpdateTimeout(priv->eventFlushTimer, 0);
+
+cleanup:
+ remoteDriverUnlock(priv);
+ return ret;
+}
+
+
/**
* remoteDomainReadEventLifecycle
*
* Read the domain lifecycle event data off the wire
*/
-static virDomainEventPtr
-remoteDomainReadEventLifecycle(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
{
- remote_domain_event_lifecycle_msg msg;
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_lifecycle_msg *msg = evdata;
virDomainPtr dom;
virDomainEventPtr event = NULL;
- memset (&msg, 0, sizeof msg);
-
- /* unmarshall parameters, and process it*/
- if (! xdr_remote_domain_event_lifecycle_msg(xdr, &msg) ) {
- remoteError(VIR_ERR_RPC, "%s",
- _("unable to demarshall lifecycle event"));
- return NULL;
- }
- dom = get_nonnull_domain(conn,msg.dom);
+ dom = get_nonnull_domain(conn, msg->dom);
if (!dom)
- return NULL;
-
- event = virDomainEventNewFromDom(dom, msg.event, msg.detail);
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_lifecycle_msg, (char *)
&msg);
+ return;
+ event = virDomainEventNewFromDom(dom, msg->event, msg->detail);
virDomainFree(dom);
- return event;
+
+ if (remoteDomainEventQueuePush(priv, event) < 0)
+ virDomainEventFree(event);
}
-static virDomainEventPtr
-remoteDomainReadEventReboot(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventReboot(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
{
- remote_domain_event_reboot_msg msg;
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_reboot_msg *msg = evdata;
virDomainPtr dom;
virDomainEventPtr event = NULL;
- memset (&msg, 0, sizeof msg);
-
- /* unmarshall parameters, and process it*/
- if (! xdr_remote_domain_event_reboot_msg(xdr, &msg) ) {
- remoteError(VIR_ERR_RPC, "%s",
- _("unable to demarshall reboot event"));
- return NULL;
- }
- dom = get_nonnull_domain(conn,msg.dom);
+ dom = get_nonnull_domain(conn, msg->dom);
if (!dom)
- return NULL;
+ return;
event = virDomainEventRebootNewFromDom(dom);
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_reboot_msg, (char *) &msg);
-
virDomainFree(dom);
- return event;
+
+ if (remoteDomainEventQueuePush(priv, event) < 0)
+ virDomainEventFree(event);
}
-static virDomainEventPtr
-remoteDomainReadEventRTCChange(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventRTCChange(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
{
- remote_domain_event_rtc_change_msg msg;
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_rtc_change_msg *msg = evdata;
virDomainPtr dom;
virDomainEventPtr event = NULL;
- memset (&msg, 0, sizeof msg);
-
- /* unmarshall parameters, and process it*/
- if (! xdr_remote_domain_event_rtc_change_msg(xdr, &msg) ) {
- remoteError(VIR_ERR_RPC, "%s",
- _("unable to demarshall reboot event"));
- return NULL;
- }
- dom = get_nonnull_domain(conn,msg.dom);
+ dom = get_nonnull_domain(conn, msg->dom);
if (!dom)
- return NULL;
-
- event = virDomainEventRTCChangeNewFromDom(dom, msg.offset);
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_rtc_change_msg, (char *)
&msg);
+ return;
+ event = virDomainEventRTCChangeNewFromDom(dom, msg->offset);
virDomainFree(dom);
- return event;
+
+ if (remoteDomainEventQueuePush(priv, event) < 0)
+ virDomainEventFree(event);
}
-static virDomainEventPtr
-remoteDomainReadEventWatchdog(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventWatchdog(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
{
- remote_domain_event_watchdog_msg msg;
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_watchdog_msg *msg = evdata;
virDomainPtr dom;
virDomainEventPtr event = NULL;
- memset (&msg, 0, sizeof msg);
-
- /* unmarshall parameters, and process it*/
- if (! xdr_remote_domain_event_watchdog_msg(xdr, &msg) ) {
- remoteError(VIR_ERR_RPC, "%s",
- _("unable to demarshall reboot event"));
- return NULL;
- }
- dom = get_nonnull_domain(conn,msg.dom);
+ dom = get_nonnull_domain(conn, msg->dom);
if (!dom)
- return NULL;
-
- event = virDomainEventWatchdogNewFromDom(dom, msg.action);
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_watchdog_msg, (char *) &msg);
+ return;
+ event = virDomainEventWatchdogNewFromDom(dom, msg->action);
virDomainFree(dom);
- return event;
+
+ if (remoteDomainEventQueuePush(priv, event) < 0)
+ virDomainEventFree(event);
}
-static virDomainEventPtr
-remoteDomainReadEventIOError(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventIOError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
{
- remote_domain_event_io_error_msg msg;
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_io_error_msg *msg = evdata;
virDomainPtr dom;
virDomainEventPtr event = NULL;
- memset (&msg, 0, sizeof msg);
-
- /* unmarshall parameters, and process it*/
- if (! xdr_remote_domain_event_io_error_msg(xdr, &msg) ) {
- remoteError(VIR_ERR_RPC, "%s",
- _("unable to demarshall reboot event"));
- return NULL;
- }
- dom = get_nonnull_domain(conn,msg.dom);
+ dom = get_nonnull_domain(conn, msg->dom);
if (!dom)
- return NULL;
+ return;
event = virDomainEventIOErrorNewFromDom(dom,
- msg.srcPath,
- msg.devAlias,
- msg.action);
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_msg, (char *) &msg);
-
+ msg->srcPath,
+ msg->devAlias,
+ msg->action);
virDomainFree(dom);
- return event;
+
+ if (remoteDomainEventQueuePush(priv, event) < 0)
+ virDomainEventFree(event);
}
-static virDomainEventPtr
-remoteDomainReadEventIOErrorReason(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventIOErrorReason(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
{
- remote_domain_event_io_error_reason_msg msg;
- virDomainPtr dom;
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_io_error_reason_msg *msg = evdata;
+ virDomainPtr dom;
virDomainEventPtr event = NULL;
- memset (&msg, 0, sizeof msg);
-
- /* unmarshall parameters, and process it*/
- if (! xdr_remote_domain_event_io_error_reason_msg(xdr, &msg) ) {
- remoteError(VIR_ERR_RPC, "%s",
- _("unable to demarshall reboot event"));
- return NULL;
- }
- dom = get_nonnull_domain(conn,msg.dom);
+ dom = get_nonnull_domain(conn,msg->dom);
if (!dom)
- return NULL;
+ return;
event = virDomainEventIOErrorReasonNewFromDom(dom,
- msg.srcPath,
- msg.devAlias,
- msg.action,
- msg.reason);
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_io_error_reason_msg, (char *)
&msg);
+ msg->srcPath,
+ msg->devAlias,
+ msg->action,
+ msg->reason);
virDomainFree(dom);
- return event;
+
+ if (remoteDomainEventQueuePush(priv, event) < 0)
+ virDomainEventFree(event);
}
-static virDomainEventPtr
-remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
+static void
+remoteDomainBuildEventGraphics(virNetClientProgramPtr prog ATTRIBUTE_UNUSED,
+ virNetClientPtr client ATTRIBUTE_UNUSED,
+ void *evdata, void *opaque)
{
- remote_domain_event_graphics_msg msg;
+ virConnectPtr conn = opaque;
+ struct private_data *priv = conn->privateData;
+ remote_domain_event_graphics_msg *msg = evdata;
virDomainPtr dom;
virDomainEventPtr event = NULL;
virDomainEventGraphicsAddressPtr localAddr = NULL;
@@ -7758,58 +7044,49 @@ remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr)
virDomainEventGraphicsSubjectPtr subject = NULL;
int i;
- memset (&msg, 0, sizeof msg);
-
- /* unmarshall parameters, and process it*/
- if (! xdr_remote_domain_event_graphics_msg(xdr, &msg) ) {
- remoteError(VIR_ERR_RPC, "%s",
- _("unable to demarshall reboot event"));
- return NULL;
- }
-
- dom = get_nonnull_domain(conn,msg.dom);
+ dom = get_nonnull_domain(conn, msg->dom);
if (!dom)
- return NULL;
+ return;
if (VIR_ALLOC(localAddr) < 0)
goto no_memory;
- localAddr->family = msg.local.family;
- if (!(localAddr->service = strdup(msg.local.service)) ||
- !(localAddr->node = strdup(msg.local.node)))
+ localAddr->family = msg->local.family;
+ if (!(localAddr->service = strdup(msg->local.service)) ||
+ !(localAddr->node = strdup(msg->local.node)))
goto no_memory;
if (VIR_ALLOC(remoteAddr) < 0)
goto no_memory;
- remoteAddr->family = msg.remote.family;
- if (!(remoteAddr->service = strdup(msg.remote.service)) ||
- !(remoteAddr->node = strdup(msg.remote.node)))
+ remoteAddr->family = msg->remote.family;
+ if (!(remoteAddr->service = strdup(msg->remote.service)) ||
+ !(remoteAddr->node = strdup(msg->remote.node)))
goto no_memory;
if (VIR_ALLOC(subject) < 0)
goto no_memory;
- if (VIR_ALLOC_N(subject->identities, msg.subject.subject_len) < 0)
+ if (VIR_ALLOC_N(subject->identities, msg->subject.subject_len) < 0)
goto no_memory;
- subject->nidentity = msg.subject.subject_len;
+ subject->nidentity = msg->subject.subject_len;
for (i = 0 ; i < subject->nidentity ; i++) {
- if (!(subject->identities[i].type = strdup(msg.subject.subject_val[i].type))
||
- !(subject->identities[i].name = strdup(msg.subject.subject_val[i].name)))
+ if (!(subject->identities[i].type =
strdup(msg->subject.subject_val[i].type)) ||
+ !(subject->identities[i].name =
strdup(msg->subject.subject_val[i].name)))
goto no_memory;
}
event = virDomainEventGraphicsNewFromDom(dom,
- msg.phase,
+ msg->phase,
localAddr,
remoteAddr,
- msg.authScheme,
+ msg->authScheme,
subject);
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
virDomainFree(dom);
- return event;
-no_memory:
- xdr_free ((xdrproc_t) &xdr_remote_domain_event_graphics_msg, (char *) &msg);
+ if (remoteDomainEventQueuePush(priv, event) < 0)
+ virDomainEventFree(event);
+ return;
+no_memory:
if (localAddr) {
VIR_FREE(localAddr->service);
VIR_FREE(localAddr->node);
@@ -7828,7 +7105,7 @@ no_memory:
VIR_FREE(subject->identities);
VIR_FREE(subject);
}
- return NULL;
+ return;
}
@@ -8165,7 +7442,7 @@ done:
return rv;
}
-
+#if 0
static struct private_stream_data *
remoteStreamOpen(virStreamPtr st,
int output ATTRIBUTE_UNUSED,
@@ -8712,7 +7989,7 @@ done:
return rv;
}
-
+#endif
static int
remoteCPUCompare(virConnectPtr conn, const char *xmlDesc,
@@ -9244,7 +8521,7 @@ done:
return rv;
}
-
+#if 0
static int
remoteDomainOpenConsole(virDomainPtr dom,
const char *devname,
@@ -9283,6 +8560,7 @@ done:
return rv;
}
+#endif
/*----------------------------------------------------------------------*/
@@ -9325,534 +8603,7 @@ done:
return rv;
}
-/*----------------------------------------------------------------------*/
-
-static struct remote_thread_call *
-prepareCall(struct private_data *priv,
- int flags,
- int proc_nr,
- xdrproc_t args_filter, char *args,
- xdrproc_t ret_filter, char *ret)
-{
- XDR xdr;
- struct remote_message_header hdr;
- struct remote_thread_call *rv;
-
- if (VIR_ALLOC(rv) < 0) {
- virReportOOMError();
- return NULL;
- }
-
- if (virCondInit(&rv->cond) < 0) {
- VIR_FREE(rv);
- remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("cannot initialize mutex"));
- return NULL;
- }
-
- /* Get a unique serial number for this message. */
- rv->serial = priv->counter++;
- rv->proc_nr = proc_nr;
- rv->ret_filter = ret_filter;
- rv->ret = ret;
- rv->want_reply = 1;
-
- if (flags & REMOTE_CALL_QEMU) {
- hdr.prog = QEMU_PROGRAM;
- hdr.vers = QEMU_PROTOCOL_VERSION;
- }
- else {
- hdr.prog = REMOTE_PROGRAM;
- hdr.vers = REMOTE_PROTOCOL_VERSION;
- }
- hdr.proc = proc_nr;
- hdr.type = REMOTE_CALL;
- hdr.serial = rv->serial;
- hdr.status = REMOTE_OK;
-
- /* Serialise header followed by args. */
- xdrmem_create (&xdr, rv->buffer+4, REMOTE_MESSAGE_MAX, XDR_ENCODE);
- if (!xdr_remote_message_header (&xdr, &hdr)) {
- remoteError(VIR_ERR_RPC, "%s", _("xdr_remote_message_header
failed"));
- goto error;
- }
-
- if (!(*args_filter) (&xdr, args)) {
- remoteError(VIR_ERR_RPC, "%s", _("marshalling args"));
- goto error;
- }
-
- /* Get the length stored in buffer. */
- rv->bufferLength = xdr_getpos (&xdr);
- xdr_destroy (&xdr);
-
- /* Length must include the length word itself (always encoded in
- * 4 bytes as per RFC 4506).
- */
- rv->bufferLength += REMOTE_MESSAGE_HEADER_XDR_LEN;
-
- /* Encode the length word. */
- xdrmem_create (&xdr, rv->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE);
- if (!xdr_u_int (&xdr, &rv->bufferLength)) {
- remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length
word)"));
- goto error;
- }
- xdr_destroy (&xdr);
-
- return rv;
-
-error:
- xdr_destroy (&xdr);
- VIR_FREE(rv);
- return NULL;
-}
-
-
-
-static int
-remoteIOWriteBuffer(struct private_data *priv,
- const char *bytes, int len)
-{
- int ret;
-
- if (priv->uses_tls) {
- tls_resend:
- ret = gnutls_record_send (priv->session, bytes, len);
- if (ret < 0) {
- if (ret == GNUTLS_E_INTERRUPTED)
- goto tls_resend;
- if (ret == GNUTLS_E_AGAIN)
- return 0;
-
- remoteError(VIR_ERR_GNUTLS_ERROR, "%s", gnutls_strerror (ret));
- return -1;
- }
- } else {
- resend:
- ret = send (priv->sock, bytes, len, 0);
- if (ret == -1) {
- if (errno == EINTR)
- goto resend;
- if (errno == EWOULDBLOCK)
- return 0;
-
- virReportSystemError(errno, "%s", _("cannot send
data"));
- return -1;
-
- }
- }
-
- return ret;
-}
-
-
-static int
-remoteIOReadBuffer(struct private_data *priv,
- char *bytes, int len)
-{
- int ret;
-
- if (priv->uses_tls) {
- tls_resend:
- ret = gnutls_record_recv (priv->session, bytes, len);
- if (ret == GNUTLS_E_INTERRUPTED)
- goto tls_resend;
- if (ret == GNUTLS_E_AGAIN)
- return 0;
-
- /* Treat 0 == EOF as an error */
- if (ret <= 0) {
- if (ret < 0)
- remoteError(VIR_ERR_GNUTLS_ERROR,
- _("failed to read from TLS socket %s"),
- gnutls_strerror (ret));
- else
- remoteError(VIR_ERR_SYSTEM_ERROR, "%s",
- _("server closed connection"));
- return -1;
- }
- } else {
- resend:
- ret = recv (priv->sock, bytes, len, 0);
- if (ret <= 0) {
- if (ret == -1) {
- if (errno == EINTR)
- goto resend;
- if (errno == EWOULDBLOCK)
- return 0;
-
- char errout[1024] = "\0";
- if (priv->errfd != -1) {
- if (saferead(priv->errfd, errout, sizeof(errout)) < 0) {
- virReportSystemError(errno, "%s",
- _("cannot recv data"));
- return -1;
- }
- }
-
- virReportSystemError(errno,
- _("cannot recv data: %s"), errout);
-
- } else {
- char errout[1024] = "\0";
- if (priv->errfd != -1) {
- if (saferead(priv->errfd, errout, sizeof(errout)) < 0) {
- remoteError(VIR_ERR_SYSTEM_ERROR,
- _("server closed connection: %s"),
- virStrerror(errno, errout, sizeof errout));
- return -1;
- }
- }
-
- remoteError(VIR_ERR_SYSTEM_ERROR,
- _("server closed connection: %s"), errout);
- }
- return -1;
- }
- }
-
- return ret;
-}
-
-
-static int
-remoteIOWriteMessage(struct private_data *priv,
- struct remote_thread_call *thecall)
-{
-#if HAVE_SASL
- if (priv->saslconn) {
- const char *output;
- unsigned int outputlen;
- int err, ret;
-
- if (!priv->saslEncoded) {
- err = sasl_encode(priv->saslconn,
- thecall->buffer + thecall->bufferOffset,
- thecall->bufferLength - thecall->bufferOffset,
- &output, &outputlen);
- if (err != SASL_OK) {
- remoteError(VIR_ERR_INTERNAL_ERROR,
- _("failed to encode SASL data: %s"),
- sasl_errstring(err, NULL, NULL));
- return -1;
- }
- priv->saslEncoded = output;
- priv->saslEncodedLength = outputlen;
- priv->saslEncodedOffset = 0;
-
- thecall->bufferOffset = thecall->bufferLength;
- }
-
- ret = remoteIOWriteBuffer(priv,
- priv->saslEncoded + priv->saslEncodedOffset,
- priv->saslEncodedLength -
priv->saslEncodedOffset);
- if (ret < 0)
- return ret;
- priv->saslEncodedOffset += ret;
-
- if (priv->saslEncodedOffset == priv->saslEncodedLength) {
- priv->saslEncoded = NULL;
- priv->saslEncodedOffset = priv->saslEncodedLength = 0;
- if (thecall->want_reply)
- thecall->mode = REMOTE_MODE_WAIT_RX;
- else
- thecall->mode = REMOTE_MODE_COMPLETE;
- }
- } else {
-#endif
- int ret;
- ret = remoteIOWriteBuffer(priv,
- thecall->buffer + thecall->bufferOffset,
- thecall->bufferLength - thecall->bufferOffset);
- if (ret < 0)
- return ret;
- thecall->bufferOffset += ret;
-
- if (thecall->bufferOffset == thecall->bufferLength) {
- thecall->bufferOffset = thecall->bufferLength = 0;
- if (thecall->want_reply)
- thecall->mode = REMOTE_MODE_WAIT_RX;
- else
- thecall->mode = REMOTE_MODE_COMPLETE;
- }
-#if HAVE_SASL
- }
-#endif
- return 0;
-}
-
-
-static int
-remoteIOHandleOutput(struct private_data *priv) {
- struct remote_thread_call *thecall = priv->waitDispatch;
-
- while (thecall &&
- thecall->mode != REMOTE_MODE_WAIT_TX)
- thecall = thecall->next;
-
- if (!thecall)
- return -1; /* Shouldn't happen, but you never know... */
-
- while (thecall) {
- int ret = remoteIOWriteMessage(priv, thecall);
- if (ret < 0)
- return ret;
-
- if (thecall->mode == REMOTE_MODE_WAIT_TX)
- return 0; /* Blocking write, to back to event loop */
-
- thecall = thecall->next;
- }
-
- return 0; /* No more calls to send, all done */
-}
-
-static int
-remoteIOReadMessage(struct private_data *priv) {
- unsigned int wantData;
-
- /* Start by reading length word */
- if (priv->bufferLength == 0)
- priv->bufferLength = 4;
-
- wantData = priv->bufferLength - priv->bufferOffset;
-
-#if HAVE_SASL
- if (priv->saslconn) {
- if (priv->saslDecoded == NULL) {
- char encoded[8192];
- int ret, err;
- ret = remoteIOReadBuffer(priv, encoded, sizeof(encoded));
- if (ret < 0)
- return -1;
- if (ret == 0)
- return 0;
-
- err = sasl_decode(priv->saslconn, encoded, ret,
- &priv->saslDecoded,
&priv->saslDecodedLength);
- if (err != SASL_OK) {
- remoteError(VIR_ERR_INTERNAL_ERROR,
- _("failed to decode SASL data: %s"),
- sasl_errstring(err, NULL, NULL));
- return -1;
- }
- priv->saslDecodedOffset = 0;
- }
-
- if ((priv->saslDecodedLength - priv->saslDecodedOffset) < wantData)
- wantData = (priv->saslDecodedLength - priv->saslDecodedOffset);
-
- memcpy(priv->buffer + priv->bufferOffset,
- priv->saslDecoded + priv->saslDecodedOffset,
- wantData);
- priv->saslDecodedOffset += wantData;
- priv->bufferOffset += wantData;
- if (priv->saslDecodedOffset == priv->saslDecodedLength) {
- priv->saslDecodedOffset = priv->saslDecodedLength = 0;
- priv->saslDecoded = NULL;
- }
-
- return wantData;
- } else {
-#endif
- int ret;
-
- ret = remoteIOReadBuffer(priv,
- priv->buffer + priv->bufferOffset,
- wantData);
- if (ret < 0)
- return -1;
- if (ret == 0)
- return 0;
-
- priv->bufferOffset += ret;
-
- return ret;
-#if HAVE_SASL
- }
-#endif
-}
-
-
-static int
-remoteIODecodeMessageLength(struct private_data *priv) {
- XDR xdr;
- unsigned int len;
-
- xdrmem_create (&xdr, priv->buffer, priv->bufferLength, XDR_DECODE);
- if (!xdr_u_int (&xdr, &len)) {
- remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word,
reply)"));
- return -1;
- }
- xdr_destroy (&xdr);
-
- if (len < REMOTE_MESSAGE_HEADER_XDR_LEN) {
- remoteError(VIR_ERR_RPC, "%s",
- _("packet received from server too small"));
- return -1;
- }
-
- /* Length includes length word - adjust to real length to read. */
- len -= REMOTE_MESSAGE_HEADER_XDR_LEN;
-
- if (len > REMOTE_MESSAGE_MAX) {
- remoteError(VIR_ERR_RPC, "%s",
- _("packet received from server too large"));
- return -1;
- }
-
- /* Extend our declared buffer length and carry
- on reading the header + payload */
- priv->bufferLength += len;
- DEBUG("Got length, now need %d total (%d more)", priv->bufferLength,
len);
- return 0;
-}
-
-
-static int
-processCallDispatchReply(virConnectPtr conn, struct private_data *priv,
- remote_message_header *hdr,
- XDR *xdr);
-
-static int
-processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
- int in_open,
- remote_message_header *hdr,
- XDR *xdr);
-
-static int
-processCallDispatchStream(virConnectPtr conn, struct private_data *priv,
- remote_message_header *hdr,
- XDR *xdr);
-
-
-static int
-processCallDispatch(virConnectPtr conn, struct private_data *priv,
- int flags) {
- XDR xdr;
- struct remote_message_header hdr;
- int len = priv->bufferLength - 4;
- int rv = -1;
- int expectedprog;
- int expectedvers;
-
- /* Length word has already been read */
- priv->bufferOffset = 4;
-
- /* Deserialise reply header. */
- xdrmem_create (&xdr, priv->buffer + priv->bufferOffset, len, XDR_DECODE);
- if (!xdr_remote_message_header (&xdr, &hdr)) {
- remoteError(VIR_ERR_RPC, "%s", _("invalid header in
reply"));
- return -1;
- }
-
- priv->bufferOffset += xdr_getpos(&xdr);
-
- expectedprog = REMOTE_PROGRAM;
- expectedvers = REMOTE_PROTOCOL_VERSION;
- if (flags & REMOTE_CALL_QEMU) {
- expectedprog = QEMU_PROGRAM;
- expectedvers = QEMU_PROTOCOL_VERSION;
- }
-
- /* Check program, version, etc. are what we expect. */
- if (hdr.prog != expectedprog) {
- remoteError(VIR_ERR_RPC,
- _("unknown program (received %x, expected %x)"),
- hdr.prog, expectedprog);
- return -1;
- }
- if (hdr.vers != expectedvers) {
- remoteError(VIR_ERR_RPC,
- _("unknown protocol version (received %x, expected %x)"),
- hdr.vers, expectedvers);
- return -1;
- }
-
-
- switch (hdr.type) {
- case REMOTE_REPLY: /* Normal RPC replies */
- rv = processCallDispatchReply(conn, priv, &hdr, &xdr);
- break;
-
- case REMOTE_MESSAGE: /* Async notifications */
- rv = processCallDispatchMessage(conn, priv, flags & REMOTE_CALL_IN_OPEN,
- &hdr, &xdr);
- break;
-
- case REMOTE_STREAM: /* Stream protocol */
- rv = processCallDispatchStream(conn, priv, &hdr, &xdr);
- break;
-
- default:
- remoteError(VIR_ERR_RPC,
- _("got unexpected RPC call %d from server"),
- hdr.proc);
- rv = -1;
- break;
- }
-
- xdr_destroy(&xdr);
- return rv;
-}
-
-
-static int
-processCallDispatchReply(virConnectPtr conn ATTRIBUTE_UNUSED,
- struct private_data *priv,
- remote_message_header *hdr,
- XDR *xdr) {
- struct remote_thread_call *thecall;
-
- /* Ok, definitely got an RPC reply now find
- out who's been waiting for it */
- thecall = priv->waitDispatch;
- while (thecall &&
- thecall->serial != hdr->serial)
- thecall = thecall->next;
-
- if (!thecall) {
- remoteError(VIR_ERR_RPC,
- _("no call waiting for reply with serial %d"),
- hdr->serial);
- return -1;
- }
-
- if (hdr->proc != thecall->proc_nr) {
- remoteError(VIR_ERR_RPC,
- _("unknown procedure (received %x, expected %x)"),
- hdr->proc, thecall->proc_nr);
- return -1;
- }
-
- /* Status is either REMOTE_OK (meaning that what follows is a ret
- * structure), or REMOTE_ERROR (and what follows is a remote_error
- * structure).
- */
- switch (hdr->status) {
- case REMOTE_OK:
- if (!(*thecall->ret_filter) (xdr, thecall->ret)) {
- remoteError(VIR_ERR_RPC, "%s", _("unmarshalling ret"));
- return -1;
- }
- thecall->mode = REMOTE_MODE_COMPLETE;
- return 0;
-
- case REMOTE_ERROR:
- memset (&thecall->err, 0, sizeof thecall->err);
- if (!xdr_remote_error (xdr, &thecall->err)) {
- remoteError(VIR_ERR_RPC, "%s", _("unmarshalling
remote_error"));
- return -1;
- }
- thecall->mode = REMOTE_MODE_ERROR;
- return 0;
-
- default:
- remoteError(VIR_ERR_RPC, _("unknown status (received %x)"),
hdr->status);
- return -1;
- }
-}
-
+#if 0
static int
processCallDispatchMessage(virConnectPtr conn, struct private_data *priv,
int in_open,
@@ -9871,31 +8622,31 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data
*priv,
switch (hdr->proc) {
case REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE:
- event = remoteDomainReadEventLifecycle(conn, xdr);
+ event = remoteDomainBuildEventLifecycle(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_REBOOT:
- event = remoteDomainReadEventReboot(conn, xdr);
+ event = remoteDomainBuildEventReboot(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE:
- event = remoteDomainReadEventRTCChange(conn, xdr);
+ event = remoteDomainBuildEventRTCChange(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_WATCHDOG:
- event = remoteDomainReadEventWatchdog(conn, xdr);
+ event = remoteDomainBuildEventWatchdog(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR:
- event = remoteDomainReadEventIOError(conn, xdr);
+ event = remoteDomainBuildEventIOError(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON:
- event = remoteDomainReadEventIOErrorReason(conn, xdr);
+ event = remoteDomainBuildEventIOErrorReason(conn, xdr);
break;
case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS:
- event = remoteDomainReadEventGraphics(conn, xdr);
+ event = remoteDomainBuildEventGraphics(conn, xdr);
break;
default:
@@ -9906,16 +8657,11 @@ processCallDispatchMessage(virConnectPtr conn, struct private_data
*priv,
if (!event)
return -1;
- if (virDomainEventQueuePush(priv->domainEvents,
- event) < 0) {
- DEBUG0("Error adding event to queue");
- virDomainEventFree(event);
- }
- virEventUpdateTimeout(priv->eventFlushTimer, 0);
-
return 0;
}
+#endif
+#if 0
static int
processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
struct private_data *priv,
@@ -10022,485 +8768,43 @@ processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED,
return -1;
}
}
-
-static int
-remoteIOHandleInput(virConnectPtr conn, struct private_data *priv,
- int flags)
-{
- /* Read as much data as is available, until we get
- * EAGAIN
- */
- for (;;) {
- int ret = remoteIOReadMessage(priv);
-
- if (ret < 0)
- return -1;
- if (ret == 0)
- return 0; /* Blocking on read */
-
- /* Check for completion of our goal */
- if (priv->bufferOffset == priv->bufferLength) {
- if (priv->bufferOffset == 4) {
- ret = remoteIODecodeMessageLength(priv);
- if (ret < 0)
- return -1;
-
- /*
- * We'll carry on around the loop to immediately
- * process the message body, because it has probably
- * already arrived. Worst case, we'll get EAGAIN on
- * next iteration.
- */
- } else {
- ret = processCallDispatch(conn, priv, flags);
- priv->bufferOffset = priv->bufferLength = 0;
- /*
- * We've completed one call, so return even
- * though there might still be more data on
- * the wire. We need to actually let the caller
- * deal with this arrived message to keep good
- * response, and also to correctly handle EOF.
- */
- return ret;
- }
- }
- }
-}
-
-/*
- * Process all calls pending dispatch/receive until we
- * get a reply to our own call. Then quit and pass the buck
- * to someone else.
- */
-static int
-remoteIOEventLoop(virConnectPtr conn,
- struct private_data *priv,
- int flags,
- struct remote_thread_call *thiscall)
-{
- struct pollfd fds[2];
- int ret;
-
- fds[0].fd = priv->sock;
- fds[1].fd = priv->wakeupReadFD;
-
- for (;;) {
- struct remote_thread_call *tmp = priv->waitDispatch;
- struct remote_thread_call *prev;
- char ignore;
-#ifdef HAVE_PTHREAD_SIGMASK
- sigset_t oldmask, blockedsigs;
-#endif
-
- fds[0].events = fds[0].revents = 0;
- fds[1].events = fds[1].revents = 0;
-
- fds[1].events = POLLIN;
- while (tmp) {
- if (tmp->mode == REMOTE_MODE_WAIT_RX)
- fds[0].events |= POLLIN;
- if (tmp->mode == REMOTE_MODE_WAIT_TX)
- fds[0].events |= POLLOUT;
-
- tmp = tmp->next;
- }
-
- if (priv->streams)
- fds[0].events |= POLLIN;
-
- /* Release lock while poll'ing so other threads
- * can stuff themselves on the queue */
- remoteDriverUnlock(priv);
-
- /* Block SIGWINCH from interrupting poll in curses programs,
- * then restore the original signal mask again immediately
- * after the call (RHBZ#567931). Same for SIGCHLD and SIGPIPE
- * at the suggestion of Paolo Bonzini and Daniel Berrange.
- */
-#ifdef HAVE_PTHREAD_SIGMASK
- sigemptyset (&blockedsigs);
- sigaddset (&blockedsigs, SIGWINCH);
- sigaddset (&blockedsigs, SIGCHLD);
- sigaddset (&blockedsigs, SIGPIPE);
- ignore_value(pthread_sigmask(SIG_BLOCK, &blockedsigs, &oldmask));
#endif
- repoll:
- ret = poll(fds, ARRAY_CARDINALITY(fds), -1);
- if (ret < 0 && errno == EAGAIN)
- goto repoll;
-
-#ifdef HAVE_PTHREAD_SIGMASK
- ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL));
-#endif
-
- remoteDriverLock(priv);
-
- if (fds[1].revents) {
- ssize_t s;
- DEBUG0("Woken up from poll by other thread");
- s = saferead(priv->wakeupReadFD, &ignore, sizeof(ignore));
- if (s < 0) {
- virReportSystemError(errno, "%s",
- _("read on wakeup fd failed"));
- goto error;
- } else if (s != sizeof(ignore)) {
- remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("read on wakeup fd failed"));
- goto error;
- }
- }
-
- if (ret < 0) {
- if (errno == EWOULDBLOCK)
- continue;
- virReportSystemError(errno,
- "%s", _("poll on socket failed"));
- goto error;
- }
-
- if (fds[0].revents & POLLOUT) {
- if (remoteIOHandleOutput(priv) < 0)
- goto error;
- }
-
- if (fds[0].revents & POLLIN) {
- if (remoteIOHandleInput(conn, priv, flags) < 0)
- goto error;
- }
-
- /* Iterate through waiting threads and if
- * any are complete then tell 'em to wakeup
- */
- tmp = priv->waitDispatch;
- prev = NULL;
- while (tmp) {
- if (tmp != thiscall &&
- (tmp->mode == REMOTE_MODE_COMPLETE ||
- tmp->mode == REMOTE_MODE_ERROR)) {
- /* Take them out of the list */
- if (prev)
- prev->next = tmp->next;
- else
- priv->waitDispatch = tmp->next;
-
- /* And wake them up....
- * ...they won't actually wakeup until
- * we release our mutex a short while
- * later...
- */
- DEBUG("Waking up sleep %d %p %p", tmp->proc_nr, tmp,
priv->waitDispatch);
- virCondSignal(&tmp->cond);
- }
- prev = tmp;
- tmp = tmp->next;
- }
-
- /* Now see if *we* are done */
- if (thiscall->mode == REMOTE_MODE_COMPLETE ||
- thiscall->mode == REMOTE_MODE_ERROR) {
- /* We're at head of the list already, so
- * remove us
- */
- priv->waitDispatch = thiscall->next;
- DEBUG("Giving up the buck %d %p %p", thiscall->proc_nr,
thiscall, priv->waitDispatch);
- /* See if someone else is still waiting
- * and if so, then pass the buck ! */
- if (priv->waitDispatch) {
- DEBUG("Passing the buck to %d %p",
priv->waitDispatch->proc_nr, priv->waitDispatch);
- virCondSignal(&priv->waitDispatch->cond);
- }
- return 0;
- }
-
-
- if (fds[0].revents & (POLLHUP | POLLERR)) {
- remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("received hangup / error event on socket"));
- goto error;
- }
- }
-
-
-error:
- priv->waitDispatch = thiscall->next;
- DEBUG("Giving up the buck due to I/O error %d %p %p", thiscall->proc_nr,
thiscall, priv->waitDispatch);
- /* See if someone else is still waiting
- * and if so, then pass the buck ! */
- if (priv->waitDispatch) {
- DEBUG("Passing the buck to %d %p", priv->waitDispatch->proc_nr,
priv->waitDispatch);
- virCondSignal(&priv->waitDispatch->cond);
- }
- return -1;
-}
-
-/*
- * This function sends a message to remote server and awaits a reply
- *
- * NB. This does not free the args structure (not desirable, since you
- * often want this allocated on the stack or else it contains strings
- * which come from the user). It does however free any intermediate
- * results, eg. the error structure if there is one.
- *
- * NB(2). Make sure to memset (&ret, 0, sizeof ret) before calling,
- * else Bad Things will happen in the XDR code.
- *
- * NB(3) You must have the private_data lock before calling this
- *
- * NB(4) This is very complicated. Due to connection cloning, multiple
- * threads can want to use the socket at once. Obviously only one of
- * them can. So if someone's using the socket, other threads are put
- * to sleep on condition variables. The existing thread may completely
- * send & receive their RPC call/reply while they're asleep. Or it
- * may only get around to dealing with sending the call. Or it may
- * get around to neither. So upon waking up from slumber, the other
- * thread may or may not have more work todo.
- *
- * We call this dance 'passing the buck'
- *
- *
http://en.wikipedia.org/wiki/Passing_the_buck
- *
- * "Buck passing or passing the buck is the action of transferring
- * responsibility or blame unto another person. It is also used as
- * a strategy in power politics when the actions of one country/
- * nation are blamed on another, providing an opportunity for war."
- *
- * NB(5) Don't Panic!
- */
-static int
-remoteIO(virConnectPtr conn,
- struct private_data *priv,
- int flags,
- struct remote_thread_call *thiscall)
-{
- int rv;
-
- DEBUG("Do proc=%d serial=%d length=%d wait=%p",
- thiscall->proc_nr, thiscall->serial,
- thiscall->bufferLength, priv->waitDispatch);
-
- /* Check to see if another thread is dispatching */
- if (priv->waitDispatch) {
- /* Stick ourselves on the end of the wait queue */
- struct remote_thread_call *tmp = priv->waitDispatch;
- char ignore = 1;
- ssize_t s;
- while (tmp && tmp->next)
- tmp = tmp->next;
- if (tmp)
- tmp->next = thiscall;
- else
- priv->waitDispatch = thiscall;
-
- /* Force other thread to wakeup from poll */
- s = safewrite(priv->wakeupSendFD, &ignore, sizeof(ignore));
- if (s < 0) {
- char errout[1024];
- remoteError(VIR_ERR_INTERNAL_ERROR,
- _("failed to wake up polling thread: %s"),
- virStrerror(errno, errout, sizeof errout));
- return -1;
- } else if (s != sizeof(ignore)) {
- remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to wake up polling thread"));
- return -1;
- }
-
- DEBUG("Going to sleep %d %p %p", thiscall->proc_nr,
priv->waitDispatch, thiscall);
- /* Go to sleep while other thread is working... */
- if (virCondWait(&thiscall->cond, &priv->lock) < 0) {
- if (priv->waitDispatch == thiscall) {
- priv->waitDispatch = thiscall->next;
- } else {
- tmp = priv->waitDispatch;
- while (tmp && tmp->next &&
- tmp->next != thiscall) {
- tmp = tmp->next;
- }
- if (tmp && tmp->next == thiscall)
- tmp->next = thiscall->next;
- }
- remoteError(VIR_ERR_INTERNAL_ERROR, "%s",
- _("failed to wait on condition"));
- return -1;
- }
-
- DEBUG("Wokeup from sleep %d %p %p", thiscall->proc_nr,
priv->waitDispatch, thiscall);
- /* Two reasons we can be woken up
- * 1. Other thread has got our reply ready for us
- * 2. Other thread is all done, and it is our turn to
- * be the dispatcher to finish waiting for
- * our reply
- */
- if (thiscall->mode == REMOTE_MODE_COMPLETE ||
- thiscall->mode == REMOTE_MODE_ERROR) {
- /*
- * We avoided catching the buck and our reply is ready !
- * We've already had 'thiscall' removed from the list
- * so just need to (maybe) handle errors & free it
- */
- goto cleanup;
- }
-
- /* Grr, someone passed the buck onto us ... */
-
- } else {
- /* We're first to catch the buck */
- priv->waitDispatch = thiscall;
- }
-
- DEBUG("We have the buck %d %p %p", thiscall->proc_nr,
priv->waitDispatch, thiscall);
- /*
- * The buck stops here!
- *
- * At this point we're about to own the dispatch
- * process...
- */
-
- /*
- * Avoid needless wake-ups of the event loop in the
- * case where this call is being made from a different
- * thread than the event loop. These wake-ups would
- * cause the event loop thread to be blocked on the
- * mutex for the duration of the call
- */
- if (priv->watch >= 0)
- virEventUpdateHandle(priv->watch, 0);
-
- rv = remoteIOEventLoop(conn, priv, flags, thiscall);
-
- if (priv->watch >= 0)
- virEventUpdateHandle(priv->watch, VIR_EVENT_HANDLE_READABLE);
-
- if (rv < 0)
- return -1;
-
-cleanup:
- DEBUG("All done with our call %d %p %p", thiscall->proc_nr,
priv->waitDispatch, thiscall);
- if (thiscall->mode == REMOTE_MODE_ERROR) {
- /* See if caller asked us to keep quiet about missing RPCs
- * eg for interop with older servers */
- if (flags & REMOTE_CALL_QUIET_MISSING_RPC &&
- thiscall->err.domain == VIR_FROM_REMOTE &&
- thiscall->err.code == VIR_ERR_RPC &&
- thiscall->err.level == VIR_ERR_ERROR &&
- thiscall->err.message &&
- STRPREFIX(*thiscall->err.message, "unknown procedure")) {
- rv = -2;
- } else if (thiscall->err.domain == VIR_FROM_REMOTE &&
- thiscall->err.code == VIR_ERR_RPC &&
- thiscall->err.level == VIR_ERR_ERROR &&
- thiscall->err.message &&
- STRPREFIX(*thiscall->err.message, "unknown procedure"))
{
- /*
- * convert missing remote entry points into the unsupported
- * feature error
- */
- virRaiseErrorFull(flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
- __FILE__, __FUNCTION__, __LINE__,
- thiscall->err.domain,
- VIR_ERR_NO_SUPPORT,
- thiscall->err.level,
- thiscall->err.str1 ? *thiscall->err.str1 : NULL,
- thiscall->err.str2 ? *thiscall->err.str2 : NULL,
- thiscall->err.str3 ? *thiscall->err.str3 : NULL,
- thiscall->err.int1,
- thiscall->err.int2,
- "%s", *thiscall->err.message);
- rv = -1;
- } else {
- virRaiseErrorFull(flags & REMOTE_CALL_IN_OPEN ? NULL : conn,
- __FILE__, __FUNCTION__, __LINE__,
- thiscall->err.domain,
- thiscall->err.code,
- thiscall->err.level,
- thiscall->err.str1 ? *thiscall->err.str1 : NULL,
- thiscall->err.str2 ? *thiscall->err.str2 : NULL,
- thiscall->err.str3 ? *thiscall->err.str3 : NULL,
- thiscall->err.int1,
- thiscall->err.int2,
- "%s", thiscall->err.message ?
*thiscall->err.message : "unknown");
- rv = -1;
- }
- xdr_free((xdrproc_t)xdr_remote_error, (char *)&thiscall->err);
- } else {
- rv = 0;
- }
- return rv;
-}
-
/*
* Serial a set of arguments into a method call message,
* send that to the server and wait for reply
*/
static int
-call (virConnectPtr conn, struct private_data *priv,
+call (virConnectPtr conn ATTRIBUTE_UNUSED,
+ struct private_data *priv,
int flags,
int proc_nr,
xdrproc_t args_filter, char *args,
xdrproc_t ret_filter, char *ret)
{
- struct remote_thread_call *thiscall;
int rv;
+ virNetClientProgramPtr prog = flags & REMOTE_CALL_QEMU ? priv->qemuProgram :
priv->remoteProgram;
+ int counter = priv->counter++;
+ priv->localUses++;
- thiscall = prepareCall(priv, flags, proc_nr, args_filter, args,
- ret_filter, ret);
-
- if (!thiscall) {
- virReportOOMError();
- return -1;
- }
-
- rv = remoteIO(conn, priv, flags, thiscall);
- VIR_FREE(thiscall);
+ /* Unlock, so that if we get any async events/stream data
+ * while processing the RPC, we don't deadlock when our
+ * callbacks for those are invoked
+ */
+ remoteDriverUnlock(priv);
+ rv = virNetClientProgramCall(prog,
+ priv->client,
+ counter,
+ proc_nr,
+ args_filter, args,
+ ret_filter, ret);
+ remoteDriverLock(priv);
+ priv->localUses--;
return rv;
}
-/** remoteDomainEventFired:
- *
- * The callback for monitoring the remote socket
- * for event data
- */
-void
-remoteDomainEventFired(int watch,
- int fd,
- int event,
- void *opaque)
-{
- virConnectPtr conn = opaque;
- struct private_data *priv = conn->privateData;
-
- remoteDriverLock(priv);
-
- /* This should be impossible, but it doesn't hurt to check */
- if (priv->waitDispatch)
- goto done;
-
- DEBUG("Event fired %d %d %d %X", watch, fd, event, event);
-
- if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) {
- DEBUG("%s : VIR_EVENT_HANDLE_HANGUP or "
- "VIR_EVENT_HANDLE_ERROR encountered", __FUNCTION__);
- virEventRemoveHandle(watch);
- priv->watch = -1;
- goto done;
- }
-
- if (fd != priv->sock) {
- virEventRemoveHandle(watch);
- priv->watch = -1;
- goto done;
- }
-
- if (remoteIOHandleInput(conn, priv, 0) < 0)
- DEBUG0("Something went wrong during async message processing");
-
-done:
- remoteDriverUnlock(priv);
-}
-
static void remoteDomainEventDispatchFunc(virConnectPtr conn,
virDomainEventPtr event,
virConnectDomainEventGenericCallback cb,
@@ -10753,7 +9057,7 @@ static virDriver remote_driver = {
remoteNodeDeviceDettach, /* nodeDeviceDettach */
remoteNodeDeviceReAttach, /* nodeDeviceReAttach */
remoteNodeDeviceReset, /* nodeDeviceReset */
- remoteDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
+ NULL, //remoteDomainMigratePrepareTunnel, /* domainMigratePrepareTunnel */
remoteIsEncrypted, /* isEncrypted */
remoteIsSecure, /* isSecure */
remoteDomainIsActive, /* domainIsActive */
@@ -10781,7 +9085,7 @@ static virDriver remote_driver = {
remoteQemuDomainMonitorCommand, /* qemuDomainMonitorCommand */
remoteDomainSetMemoryParameters, /* domainSetMemoryParameters */
remoteDomainGetMemoryParameters, /* domainGetMemoryParameters */
- remoteDomainOpenConsole, /* domainOpenConsole */
+ NULL, //remoteDomainOpenConsole, /* domainOpenConsole */
};
static virNetworkDriver network_driver = {
--
1.7.2.3