On 06/27/2011 08:24 AM, Daniel P. Berrange wrote: > 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 | 5 +- > src/remote/remote_driver.c | 3452 ++++++++------------------------------------ > src/rpc/gendispatch.pl | 14 +- > 3 files changed, 586 insertions(+), 2885 deletions(-) > @@ -1222,6 +1222,7 @@ endif > libvirt_net_rpc_la_CFLAGS = \ > $(GNUTLS_CFLAGS) \ > $(SASL_CFLAGS) \ > + $(XDR_CFLAGS) \ Should this hunk be done as a separate patch? > +++ b/src/remote/remote_driver.c > @@ -23,51 +23,14 @@ > +#include "virnetclient.h" > +#include "virnetclientprogram.h" > +#include "virnetclientstream.h" > #include "virterror_internal.h" > #include "logging.h" > #include "datatypes.h" 'make syntax-check' is calling you for not removing the now-unused #include "ignore-value.h". Aargh. This needs yet another rebase to pick up the revert of BlockPull patches: remote/remote_driver.c:263:7: error: 'REMOTE_PROC_DOMAIN_EVENT_BLOCK_PULL' undeclared here (not in a function) remote/remote_driver.c:265:14: error: 'remote_domain_event_block_pull_msg' undeclared here (not in a function) remote/remote_driver.c:266:18: error: 'xdr_remote_domain_event_block_pull_msg' undeclared here (not in a function) cc1: warnings being treated as errors remote/remote_driver.c:222:1: error: 'remoteDomainBuildEventBlockPull' used but never defined > @@ -107,119 +70,27 @@ > > static int inside_daemon = 0; > > -struct remote_thread_call; > - > - > -enum { > - REMOTE_MODE_WAIT_TX, > - REMOTE_MODE_WAIT_RX, > - REMOTE_MODE_COMPLETE, > - REMOTE_MODE_ERROR, > -}; Replaced by virnetclient.c, but that enum only has MODE_WAIT_TX, MODE_WAIT_RX, and MODE_COMPLETE - I'm hoping that dropping the MODE_ERROR works out. > +static void > +remoteDomainBuildEventLifecycle(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, > + virNetClientPtr client ATTRIBUTE_UNUSED, > + void *evdata, void *opaque); Is it worth rearranging this file to be in topological order, to avoid having to use quite as many forward declarations? But that should be a separate followup patch. > @@ -524,12 +431,6 @@ 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 if (STRCASEEQ(var->name, "pkipath")) { I'm not sure why this hunk is here. > > /*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_DEBUG("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()); > @@ -698,131 +544,59 @@ 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); > + if (!(priv->client = virNetClientNewUNIX(sockname, > + flags & VIR_DRV_OPEN_REMOTE_AUTOSTART, > + remoteFindDaemonPath()))) > 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); > - goto failed; > - } > - > break; > - } > > - case trans_ssh: { > - cmd = virCommandNew(command ? command : "ssh"); > - > - /* Generate the final command argv[] array. > - * ssh [-p $port] [-l $username] $hostname $netcat -U $sockname */ > + case trans_ssh: > + command = command ? command : strdup ("ssh"); > + if (command == NULL) > + goto out_of_memory; > > - if (port) { > - virCommandAddArgList(cmd, "-p", port, NULL); > - } > - if (username) { > - virCommandAddArgList(cmd, "-l", username, NULL); > - } > - if (no_tty) { > - virCommandAddArgList(cmd, "-T", "-o", "BatchMode=yes", "-e", > - "none", 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; > } > - virCommandAddArgList(cmd, priv->hostname, netcat ? netcat : "nc", > - "-U", (sockname ? sockname : > - (flags & VIR_CONNECT_RO > - ? LIBVIRTD_PRIV_UNIX_SOCKET_RO > - : LIBVIRTD_PRIV_UNIX_SOCKET)), NULL); > - > - 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")); > + if (!(priv->client = virNetClientNewSSH(priv->hostname, > + port, > + command, > + username, > + no_tty, > + netcat ? netcat : "nc", > + sockname))) > goto failed; > - } > > - if (pipe(errfd) == -1) { > - virReportSystemError(errno, "%s", > - _("unable to create socket pair")); > - goto failed; > - } > + priv->is_secure = 1; > + break; > > - virCommandSetInputFD(cmd, sv[1]); > - virCommandSetOutputFD(cmd, &(sv[1])); > - virCommandSetErrorFD(cmd, &(errfd[1])); > - virCommandClearCaps(cmd); > - if (virCommandRunAsync(cmd, &pid) < 0) > + case trans_ext: { > + char const *cmd_argv[] = { command, NULL }; > + if (!(priv->client = virNetClientNewExternal(cmd_argv))) > goto failed; > > - /* Parent continues here. */ > - VIR_FORCE_CLOSE(sv[1]); > - VIR_FORCE_CLOSE(errfd[1]); > - priv->sock = sv[0]; > - priv->errfd = errfd[0]; > - priv->pid = pid; > - > /* 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,38 +608,36 @@ doRemoteOpen (virConnectPtr conn, > goto failed; > > #endif /* WIN32 */ > - > } /* switch (transport) */ > > - if (virSetNonBlock(priv->sock) < 0) { > - virReportSystemError(errno, "%s", > - _("unable to make socket non-blocking")); > + if (!(priv->remoteProgram = virNetClientProgramNew(REMOTE_PROGRAM, > + REMOTE_PROTOCOL_VERSION, > + remoteDomainEvents, > + ARRAY_CARDINALITY(remoteDomainEvents), > + conn))) > goto failed; > - } > - > - if ((priv->errfd != -1) && virSetNonBlock(priv->errfd) < 0) { > - virReportSystemError(errno, "%s", > - _("unable to make socket non-blocking")); > + if (!(priv->qemuProgram = virNetClientProgramNew(QEMU_PROGRAM, > + QEMU_PROTOCOL_VERSION, > + NULL, > + 0, > + NULL))) > goto failed; > - } > > - if (pipe(wakeupFD) < 0) { > - virReportSystemError(errno, "%s", > - _("unable to make pipe")); > + if (virNetClientAddProgram(priv->client, priv->remoteProgram) < 0 || > + virNetClientAddProgram(priv->client, priv->qemuProgram) < 0) > goto failed; > - } > - priv->wakeupReadFD = wakeupFD[0]; > - priv->wakeupSendFD = wakeupFD[1]; > > /* Try and authenticate with server */ > - if (remoteAuthenticate(conn, priv, 1, auth, authtype) == -1) > + VIR_DEBUG("Trying authentication"); > + if (remoteAuthenticate(conn, priv, auth, authtype) == -1) > goto failed; > > /* Finally we can call the remote side's open function. */ > { > remote_open_args args = { &name, flags }; > > - if (call (conn, priv, REMOTE_CALL_IN_OPEN, REMOTE_PROC_OPEN, > + VIR_DEBUG("Trying to open URI %s", name); > + if (call (conn, priv, 0, REMOTE_PROC_OPEN, > (xdrproc_t) xdr_remote_open_args, (char *) &args, > (xdrproc_t) xdr_void, (char *) NULL) == -1) > goto failed; > @@ -874,26 +646,14 @@ doRemoteOpen (virConnectPtr conn, > /* Now try and find out what URI the daemon used */ > if (conn->uri == NULL) { > remote_get_uri_ret uriret; > - int urierr; > > + VIR_DEBUG("Trying to query remote URI"); > memset (&uriret, 0, sizeof uriret); > - urierr = call (conn, priv, > - REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC, > - REMOTE_PROC_GET_URI, > - (xdrproc_t) xdr_void, (char *) NULL, > - (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret); > - if (urierr == -2) { > - /* Should not really happen, since we only probe local libvirtd's, > - & the library should always match the daemon. Only case is post > - RPM upgrade where an old daemon instance is still running with > - new client. Too bad. It is not worth the hassle to fix this */ > - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", > - _("unable to auto-detect URI")); > - goto failed; > - } > - if (urierr == -1) { > + if (call (conn, priv, 0, > + REMOTE_PROC_GET_URI, > + (xdrproc_t) xdr_void, (char *) NULL, > + (xdrproc_t) xdr_remote_get_uri_ret, (char *) &uriret) < 0) > goto failed; > - } > > VIR_DEBUG("Auto-probed URI is %s", uriret.uri); > conn->uri = xmlParseURI(uriret.uri); > @@ -904,27 +664,11 @@ doRemoteOpen (virConnectPtr conn, > } > } > > - /* Set up a callback to listen on the socket data */ > - if ((priv->watch = virEventAddHandle(priv->sock, > - VIR_EVENT_HANDLE_READABLE, > - remoteDomainEventFired, > - conn, NULL)) < 0) { > - VIR_DEBUG("virEventAddHandle failed: No addHandleImpl defined." > - " continuing without events."); > - priv->watch = -1; > - } > - > - priv->domainEventState = virDomainEventStateNew(remoteDomainEventQueueFlush, > - conn, > - NULL, > - false); > - if (!priv->domainEventState) { > + if (!(priv->domainEventState = virDomainEventStateNew(remoteDomainEventQueueFlush, > + conn, > + NULL, > + false))) > goto failed; > - } > - if (priv->domainEventState->timer < 0 && priv->watch != -1) { > - virEventRemoveHandle(priv->watch); > - priv->watch = -1; > - } > > /* Successful. */ > retcode = VIR_DRV_OPEN_SUCCESS; > @@ -938,7 +682,6 @@ doRemoteOpen (virConnectPtr conn, > VIR_FREE(netcat); > VIR_FREE(username); > VIR_FREE(port); > - virCommandFree(cmd); > VIR_FREE(pkipath); > > return retcode; > @@ -949,30 +692,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; > @@ -995,9 +716,6 @@ remoteAllocPrivateData(void) > } > remoteDriverLock(priv); > priv->localUses = 1; > - priv->watch = -1; > - priv->sock = -1; > - priv->errfd = -1; > > return priv; > } > @@ -1109,577 +827,139 @@ 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) > +doRemoteClose (virConnectPtr conn, struct private_data *priv) > { > - if (access(file, R_OK)) { > - virReportSystemError(errno, > - _("Cannot access %s '%s'"), > - type, file); > + if (call (conn, priv, 0, REMOTE_PROC_CLOSE, > + (xdrproc_t) xdr_void, (char *) NULL, > + (xdrproc_t) xdr_void, (char *) NULL) == -1) > return -1; > - } > - return 0; > -} > > + virNetTLSContextFree(priv->tls); > + priv->tls = NULL; > + virNetClientFree(priv->client); > + priv->client = NULL; > + virNetClientProgramFree(priv->remoteProgram); > + virNetClientProgramFree(priv->qemuProgram); > + priv->remoteProgram = priv->qemuProgram = NULL; > + > + /* Free hostname copy */ > + VIR_FREE(priv->hostname); > + > + /* See comment for remoteType. */ > + VIR_FREE(priv->type); > + > + virDomainEventStateFree(priv->domainEventState); > > -static void remote_debug_gnutls_log(int level, const char* str) { > - VIR_DEBUG("%d %s", level, str); > + return 0; > } > > static int > -initialize_gnutls(char *pkipath, int flags) > +remoteClose (virConnectPtr conn) > { > - static int initialized = 0; > - int err; > - char *gnutlsdebug; > - char *libvirt_cacert = NULL; > - char *libvirt_clientkey = NULL; > - char *libvirt_clientcert = NULL; > - int ret = -1; > - char *userdir = NULL; > - char *user_pki_path = NULL; > - > - if (initialized) return 0; > - > - gnutls_global_init (); > + int ret = 0; > + struct private_data *priv = conn->privateData; > > - 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); > + 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); > > - /* 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; > - } > + return ret; > +} > > - if (pkipath) { > - if ((virAsprintf(&libvirt_cacert, "%s/%s", pkipath, > - "cacert.pem")) < 0) > - goto out_of_memory; > > - if ((virAsprintf(&libvirt_clientkey, "%s/%s", pkipath, > - "clientkey.pem")) < 0) > - goto out_of_memory; > +/* Unfortunately this function is defined to return a static string. > + * Since the remote end always answers with the same type (for a > + * single connection anyway) we cache the type in the connection's > + * private data, and free it when we close the connection. > + * > + * See also: > + * http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html > + */ > +static const char * > +remoteType (virConnectPtr conn) > +{ > + char *rv = NULL; > + remote_get_type_ret ret; > + struct private_data *priv = conn->privateData; > > - if ((virAsprintf(&libvirt_clientcert, "%s/%s", pkipath, > - "clientcert.pem")) < 0) > - goto out_of_memory; > - } else if (flags & VIR_DRV_OPEN_REMOTE_USER || getuid() > 0) { > - userdir = virGetUserDirectory(getuid()); > + remoteDriverLock(priv); > > - if (!userdir) > - goto out_of_memory; > + /* Cached? */ > + if (priv->type) { > + rv = priv->type; > + goto done; > + } > > - if (virAsprintf(&user_pki_path, "%s/.pki/libvirt", userdir) < 0) > - goto out_of_memory; > + memset (&ret, 0, sizeof ret); > + if (call (conn, priv, 0, REMOTE_PROC_GET_TYPE, > + (xdrproc_t) xdr_void, (char *) NULL, > + (xdrproc_t) xdr_remote_get_type_ret, (char *) &ret) == -1) > + goto done; > > - if ((virAsprintf(&libvirt_cacert, "%s/%s", user_pki_path, > - "cacert.pem")) < 0) > - goto out_of_memory; > + /* Stash. */ > + rv = priv->type = ret.type; > > - if ((virAsprintf(&libvirt_clientkey, "%s/%s", user_pki_path, > - "clientkey.pem")) < 0) > - goto out_of_memory; > +done: > + remoteDriverUnlock(priv); > + return rv; > +} > > - if ((virAsprintf(&libvirt_clientcert, "%s/%s", user_pki_path, > - "clientcert.pem")) < 0) > - goto out_of_memory; > +static int remoteIsSecure(virConnectPtr conn) > +{ > + int rv = -1; > + struct private_data *priv = conn->privateData; > + remote_is_secure_ret ret; > + remoteDriverLock(priv); > > - /* Use the default location of the CA certificate if it > - * cannot be found in $HOME/.pki/libvirt > - */ > - if (!virFileExists(libvirt_cacert)) { > - VIR_FREE(libvirt_cacert); > + memset (&ret, 0, sizeof ret); > + if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE, > + (xdrproc_t) xdr_void, (char *) NULL, > + (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1) > + goto done; > > - libvirt_cacert = strdup(LIBVIRT_CACERT); > - if (!libvirt_cacert) goto out_of_memory; > - } > + /* We claim to be secure, if the remote driver > + * transport itself is secure, and the remote > + * HV connection is secure > + * > + * ie, we don't want to claim to be secure if the > + * remote driver is used to connect to a XenD > + * driver using unencrypted HTTP:/// access > + */ > + rv = priv->is_secure && ret.secure ? 1 : 0; > > - /* Use default location as long as one of > - * client key, and client certificate cannot be found in > - * $HOME/.pki/libvirt, we don't want to make user confused > - * with one file is here, the other is there. > - */ > - if (!virFileExists(libvirt_clientkey) || > - !virFileExists(libvirt_clientcert)) { > - VIR_FREE(libvirt_clientkey); > - VIR_FREE(libvirt_clientcert); > - > - libvirt_clientkey = strdup(LIBVIRT_CLIENTKEY); > - if (!libvirt_clientkey) goto out_of_memory; > - > - libvirt_clientcert = strdup(LIBVIRT_CLIENTCERT); > - if (!libvirt_clientcert) goto out_of_memory; > - } > - } else { > - libvirt_cacert = strdup(LIBVIRT_CACERT); > - if (!libvirt_cacert) goto out_of_memory; > +done: > + remoteDriverUnlock(priv); > + return rv; > +} > > - libvirt_clientkey = strdup(LIBVIRT_CLIENTKEY); > - if (!libvirt_clientkey) goto out_of_memory; > +static int remoteIsEncrypted(virConnectPtr conn) > +{ > + int rv = -1; > + int encrypted = 0; > + struct private_data *priv = conn->privateData; > + remote_is_secure_ret ret; > + remoteDriverLock(priv); > > - libvirt_clientcert = strdup(LIBVIRT_CLIENTCERT); > - if (!libvirt_clientcert) goto out_of_memory; > - } > - > - if (check_cert_file("CA certificate", libvirt_cacert) < 0) > - goto error; > - if (check_cert_file("client key", libvirt_clientkey) < 0) > - goto error; > - if (check_cert_file("client certificate", libvirt_clientcert) < 0) > - goto error; > - > - /* Set the trusted CA cert. */ > - VIR_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': %s"), > - libvirt_cacert, gnutls_strerror (err)); > - goto error; > - } > - > - /* Set the client certificate and private key. */ > - VIR_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 '%s' and/or " > - "certificate '%s': %s"), libvirt_clientkey, > - libvirt_clientcert, gnutls_strerror (err)); > - goto error; > - } > - > - initialized = 1; > - ret = 0; > - > -cleanup: > - VIR_FREE(libvirt_cacert); > - VIR_FREE(libvirt_clientkey); > - VIR_FREE(libvirt_clientcert); > - VIR_FREE(userdir); > - VIR_FREE(user_pki_path); > - return ret; > - > -error: > - ret = -1; > - goto cleanup; > - > -out_of_memory: > - ret = -1; > - virReportOOMError(); > - goto cleanup; > -} > - > -static int verify_certificate (virConnectPtr conn, struct private_data *priv, gnutls_session_t session); > - > -#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); > -} > - > -static ssize_t > -custom_gnutls_pull(void *s, void *buf, size_t len) > -{ > - return recv((size_t)s, buf, len, 0); > -} > -#endif > - > -static gnutls_session_t > -negotiate_gnutls_on_connection (virConnectPtr conn, > - struct private_data *priv, > - int no_verify) > -{ > - bool success = false; > - 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; > - } > - > - /* 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)); > - goto cleanup; > - } > - > - /* 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)); > - goto cleanup; > - } > - > - gnutls_transport_set_ptr (session, > - (gnutls_transport_ptr_t) (long) priv->sock); > - > -#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 > - > - /* 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)); > - goto cleanup; > - } > - > - /* Verify certificate. */ > - if (verify_certificate (conn, priv, session) == -1) { > - VIR_DEBUG("failed to verify peer's certificate"); > - if (!no_verify) > - goto cleanup; > - } > - > - /* 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)); > - goto cleanup; > - } > - if (len != 1 || buf[0] != '\1') { > - remoteError(VIR_ERR_RPC, "%s", > - _("server verification (of our certificate or IP " > - "address) failed")); > - goto cleanup; > - } > - > -#if 0 > - /* Print session info. */ > - print_info (session); > -#endif > - > - success = true; > - > -cleanup: > - if (!success) { > - gnutls_deinit(session); > - session = NULL; > - } > - > - 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) > -{ > - /* Remove timer before closing the connection, to avoid possible > - * remoteDomainEventFired with a free'd connection */ > - if (priv->domainEventState->timer >= 0) { > - virEventRemoveTimeout(priv->domainEventState->timer); > - virEventRemoveHandle(priv->watch); > - priv->watch = -1; > - priv->domainEventState->timer = -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); > - > - virDomainEventStateFree(priv->domainEventState); > - > - 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; > -} > - > -/* Unfortunately this function is defined to return a static string. > - * Since the remote end always answers with the same type (for a > - * single connection anyway) we cache the type in the connection's > - * private data, and free it when we close the connection. > - * > - * See also: > - * http://www.redhat.com/archives/libvir-list/2007-February/msg00096.html > - */ > -static const char * > -remoteType (virConnectPtr conn) > -{ > - char *rv = NULL; > - remote_get_type_ret ret; > - struct private_data *priv = conn->privateData; > - > - remoteDriverLock(priv); > - > - /* Cached? */ > - if (priv->type) { > - rv = priv->type; > - goto done; > - } > - > - memset (&ret, 0, sizeof ret); > - if (call (conn, priv, 0, REMOTE_PROC_GET_TYPE, > - (xdrproc_t) xdr_void, (char *) NULL, > - (xdrproc_t) xdr_remote_get_type_ret, (char *) &ret) == -1) > - goto done; > - > - /* Stash. */ > - rv = priv->type = ret.type; > - > -done: > - remoteDriverUnlock(priv); > - return rv; > -} > - > -static int remoteIsSecure(virConnectPtr conn) > -{ > - int rv = -1; > - struct private_data *priv = conn->privateData; > - remote_is_secure_ret ret; > - remoteDriverLock(priv); > - > - memset (&ret, 0, sizeof ret); > - if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE, > - (xdrproc_t) xdr_void, (char *) NULL, > - (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1) > - goto done; > - > - /* We claim to be secure, if the remote driver > - * transport itself is secure, and the remote > - * HV connection is secure > - * > - * ie, we don't want to claim to be secure if the > - * remote driver is used to connect to a XenD > - * driver using unencrypted HTTP:/// access > - */ > - rv = priv->is_secure && ret.secure ? 1 : 0; > - > -done: > - remoteDriverUnlock(priv); > - return rv; > -} > - > -static int remoteIsEncrypted(virConnectPtr conn) > -{ > - int rv = -1; > - int encrypted = 0; > - struct private_data *priv = conn->privateData; > - remote_is_secure_ret ret; > - remoteDriverLock(priv); > - > - memset (&ret, 0, sizeof ret); > - if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE, > - (xdrproc_t) xdr_void, (char *) NULL, > - (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1) > - goto done; > - > - if (priv->uses_tls) > - encrypted = 1; > -#if HAVE_SASL > - else if (priv->saslconn) > - encrypted = 1; > -#endif > + memset (&ret, 0, sizeof ret); > + if (call (conn, priv, 0, REMOTE_PROC_IS_SECURE, > + (xdrproc_t) xdr_void, (char *) NULL, > + (xdrproc_t) xdr_remote_is_secure_ret, (char *) &ret) == -1) > + goto done; > > + if (virNetClientIsEncrypted(priv->client)) > + encrypted = 1; > > /* We claim to be encrypted, if the remote driver > * transport itself is encrypted, and the remote > @@ -2967,7 +2247,6 @@ remoteNWFilterClose(virConnectPtr conn) > > static int > remoteAuthenticate (virConnectPtr conn, struct private_data *priv, > - int in_open ATTRIBUTE_UNUSED, > virConnectAuthPtr auth ATTRIBUTE_UNUSED, > const char *authtype) > { > @@ -2975,16 +2254,19 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, > int err, type = REMOTE_AUTH_NONE; > > memset(&ret, 0, sizeof ret); > - err = call (conn, priv, > - REMOTE_CALL_IN_OPEN | REMOTE_CALL_QUIET_MISSING_RPC, > + err = call (conn, priv, 0, > REMOTE_PROC_AUTH_LIST, > (xdrproc_t) xdr_void, (char *) NULL, > (xdrproc_t) xdr_remote_auth_list_ret, (char *) &ret); > - if (err == -2) /* Missing RPC - old server - ignore */ > - return 0; > - > - if (err < 0) > + if (err < 0) { > + virErrorPtr verr = virGetLastError(); > + if (verr && verr->code == VIR_ERR_NO_SUPPORT) { > + /* Missing RPC - old server - ignore */ > + virResetLastError(); > + return 0; > + } > return -1; > + } > > if (ret.types.types_len == 0) > return 0; > @@ -3023,7 +2305,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, > STRCASEEQLEN(authtype, "sasl.", 5)) > mech = authtype + 5; > > - if (remoteAuthSASL(conn, priv, in_open, auth, mech) < 0) { > + if (remoteAuthSASL(conn, priv, auth, mech) < 0) { > VIR_FREE(ret.types.types_val); > return -1; > } > @@ -3033,7 +2315,7 @@ remoteAuthenticate (virConnectPtr conn, struct private_data *priv, > > #if HAVE_POLKIT > case REMOTE_AUTH_POLKIT: > - if (remoteAuthPolkit(conn, priv, in_open, auth) < 0) { > + if (remoteAuthPolkit(conn, priv, auth) < 0) { > VIR_FREE(ret.types.types_val); > return -1; > } > @@ -3225,11 +2507,9 @@ static void remoteAuthFillInteract(virConnectCredentialPtr cred, > /* Perform the SASL authentication process > */ > static int > -remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, > +remoteAuthSASL (virConnectPtr conn, struct private_data *priv, > 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; > @@ -3237,48 +2517,22 @@ 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; > + virNetSASLContextPtr saslCtxt; > + virNetSASLSessionPtr sasl; > > VIR_DEBUG("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) > + if (!(saslCtxt = virNetSASLContextNewClient())) > goto cleanup; > > if (auth) { > @@ -3289,63 +2543,37 @@ 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 = virNetSASLSessionNewClient(saslCtxt, > + "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 */ > > VIR_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 (virNetSASLSessionExtKeySize(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 (virNetSASLSessionSecProps(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); > - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_INIT, > + if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_INIT, > (xdrproc_t) xdr_void, (char *)NULL, > (xdrproc_t) xdr_remote_auth_sasl_init_ret, (char *) &iret) != 0) > goto cleanup; > @@ -3365,22 +2593,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, > restart: > /* Start the auth negotiation on the client end first */ > VIR_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 = virNetSASLSessionClientStart(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_SASL_INTERACT) { > const char *msg; > if (cred) { > remoteAuthFreeCredentials(cred, ncred); > @@ -3410,7 +2632,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 */ > @@ -3419,11 +2641,12 @@ 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; > - VIR_DEBUG("Server start negotiation with mech %s. Data %d bytes %p", mech, clientoutlen, clientout); > + VIR_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); > - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_SASL_START, > + if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_START, > (xdrproc_t) xdr_remote_auth_sasl_start_args, (char *) &sargs, > (xdrproc_t) xdr_remote_auth_sasl_start_ret, (char *) &sret) != 0) > goto cleanup; > @@ -3433,27 +2656,23 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, > serverin = sret.nil ? NULL : sret.data.data_val; > serverinlen = sret.data.data_len; > VIR_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 = virNetSASLSessionClientStep(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_SASL_INTERACT) { > const char *msg; > if (cred) { > remoteAuthFreeCredentials(cred, ncred); > @@ -3479,10 +2698,11 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, > } > > VIR_FREE(serverin); > - VIR_DEBUG("Client step result %d. Data %d bytes %p", err, clientoutlen, clientout); > + VIR_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_SASL_COMPLETE) > break; > > /* Not done, prepare to talk with the server for another iteration */ > @@ -3491,10 +2711,11 @@ 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; > - VIR_DEBUG("Server step with %d bytes %p", clientoutlen, clientout); > + VIR_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, > + if (call (conn, priv, 0, REMOTE_PROC_AUTH_SASL_STEP, > (xdrproc_t) xdr_remote_auth_sasl_step_args, (char *) &pargs, > (xdrproc_t) xdr_remote_auth_sasl_step_ret, (char *) &pret) != 0) > goto cleanup; > @@ -3505,10 +2726,10 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, > serverinlen = pret.data.data_len; > > VIR_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_SASL_COMPLETE) { > VIR_FREE(serverin); > break; > } > @@ -3516,14 +2737,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 = virNetSASLSessionGetKeySize(sasl)) < 0) > goto cleanup; > - } > - ssf = *(const int *)val; > + > VIR_DEBUG("SASL SSF value %d", ssf); > if (ssf < 56) { /* 56 == DES level, good for Kerberos */ > remoteError(VIR_ERR_AUTH_FAILED, > @@ -3534,18 +2750,16 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, > } > > VIR_DEBUG("SASL authentication complete"); > - priv->saslconn = saslconn; > + virNetClientSetSASLSession(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); > + virNetSASLSessionFree(sasl); > + virNetSASLContextFree(saslCtxt); > > return ret; > } > @@ -3555,14 +2769,14 @@ remoteAuthSASL (virConnectPtr conn, struct private_data *priv, int in_open, > #if HAVE_POLKIT > # if HAVE_POLKIT1 > static int > -remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, > +remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, > virConnectAuthPtr auth ATTRIBUTE_UNUSED) > { > remote_auth_polkit_ret ret; > VIR_DEBUG("Client initialize PolicyKit-1 authentication"); > > memset (&ret, 0, sizeof ret); > - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT, > + if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT, > (xdrproc_t) xdr_void, (char *)NULL, > (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) { > return -1; /* virError already set by call */ > @@ -3575,7 +2789,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, > /* Perform the PolicyKit authentication process > */ > static int > -remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, > +remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, > virConnectAuthPtr auth) > { > remote_auth_polkit_ret ret; > @@ -3613,7 +2827,7 @@ remoteAuthPolkit (virConnectPtr conn, struct private_data *priv, int in_open, > } > > memset (&ret, 0, sizeof ret); > - if (call (conn, priv, in_open, REMOTE_PROC_AUTH_POLKIT, > + if (call (conn, priv, 0, REMOTE_PROC_AUTH_POLKIT, > (xdrproc_t) xdr_void, (char *)NULL, > (xdrproc_t) xdr_remote_auth_polkit_ret, (char *) &ret) != 0) { > return -1; /* virError already set by call */ > @@ -3694,184 +2908,155 @@ done: > return rv; > } > > -/** > - * 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); > - > - /* unmarshal parameters, and process it*/ > - if (! xdr_remote_domain_event_lifecycle_msg(xdr, &msg) ) { > - remoteError(VIR_ERR_RPC, "%s", > - _("Unable to demarshal 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; > + > + remoteDomainEventQueue(priv, 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); > - > - /* unmarshal parameters, and process it*/ > - if (! xdr_remote_domain_event_reboot_msg(xdr, &msg) ) { > - remoteError(VIR_ERR_RPC, "%s", > - _("Unable to demarshal 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; > + > + remoteDomainEventQueue(priv, 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); > - > - /* unmarshal parameters, and process it*/ > - if (! xdr_remote_domain_event_rtc_change_msg(xdr, &msg) ) { > - remoteError(VIR_ERR_RPC, "%s", > - _("Unable to demarshal RTC change 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; > + > + remoteDomainEventQueue(priv, 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); > - > - /* unmarshal parameters, and process it*/ > - if (! xdr_remote_domain_event_watchdog_msg(xdr, &msg) ) { > - remoteError(VIR_ERR_RPC, "%s", > - _("Unable to demarshal watchdog 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; > + > + remoteDomainEventQueue(priv, 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); > - > - /* unmarshal parameters, and process it*/ > - if (! xdr_remote_domain_event_io_error_msg(xdr, &msg) ) { > - remoteError(VIR_ERR_RPC, "%s", > - _("Unable to demarshal IO error 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; > + > + remoteDomainEventQueue(priv, 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; > + 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); > - > - /* unmarshal parameters, and process it*/ > - if (! xdr_remote_domain_event_io_error_reason_msg(xdr, &msg) ) { > - remoteError(VIR_ERR_RPC, "%s", > - _("Unable to demarshal IO error reason 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; > + > + remoteDomainEventQueue(priv, 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; > @@ -3879,58 +3064,48 @@ remoteDomainReadEventGraphics(virConnectPtr conn, XDR *xdr) > virDomainEventGraphicsSubjectPtr subject = NULL; > int i; > > - memset (&msg, 0, sizeof msg); > - > - /* unmarshal parameters, and process it*/ > - if (! xdr_remote_domain_event_graphics_msg(xdr, &msg) ) { > - remoteError(VIR_ERR_RPC, "%s", > - _("Unable to demarshal graphics 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); > + remoteDomainEventQueue(priv, event); > + return; > > +no_memory: > if (localAddr) { > VIR_FREE(localAddr->service); > VIR_FREE(localAddr->node); > @@ -3949,34 +3124,31 @@ no_memory: > VIR_FREE(subject->identities); > VIR_FREE(subject); > } > - return NULL; > + return; > } > > > -static virDomainEventPtr > -remoteDomainReadEventControlError(virConnectPtr conn, XDR *xdr) > +static void > +remoteDomainBuildEventControlError(virNetClientProgramPtr prog ATTRIBUTE_UNUSED, > + virNetClientPtr client ATTRIBUTE_UNUSED, > + void *evdata, void *opaque) > { > - remote_domain_event_control_error_msg msg; > + virConnectPtr conn = opaque; > + struct private_data *priv = conn->privateData; > + remote_domain_event_control_error_msg *msg = evdata; > virDomainPtr dom; > virDomainEventPtr event = NULL; > - memset (&msg, 0, sizeof msg); > - > - /* unmarshall parameters, and process it*/ > - if (! xdr_remote_domain_event_control_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 = virDomainEventControlErrorNewFromDom(dom); > xdr_free ((xdrproc_t) &xdr_remote_domain_event_control_error_msg, (char *) &msg); > > virDomainFree(dom); > - return event; > + > + remoteDomainEventQueue(priv, event); > } > > > @@ -4020,195 +3192,6 @@ done: > return rv; > } > > -static struct private_stream_data * > -remoteStreamOpen(virStreamPtr st, > - unsigned int proc_nr, > - unsigned int serial) > -{ > - struct private_data *priv = st->conn->privateData; > - struct private_stream_data *stpriv; > - > - if (VIR_ALLOC(stpriv) < 0) { > - virReportOOMError(); > - return NULL; > - } > - > - /* Initialize call object used to receive replies */ > - stpriv->proc_nr = proc_nr; > - stpriv->serial = serial; > - > - stpriv->next = priv->streams; > - priv->streams = stpriv; > - > - return stpriv; > -} > - > - > -static void > -remoteStreamEventTimerUpdate(struct private_stream_data *privst) > -{ > - if (!privst->cb) > - return; > - > - VIR_DEBUG("Check timer offset=%d %d", privst->incomingOffset, privst->cbEvents); > - if ((privst->incomingOffset && > - (privst->cbEvents & VIR_STREAM_EVENT_READABLE)) || > - (privst->cbEvents & VIR_STREAM_EVENT_WRITABLE)) { > - VIR_DEBUG("Enabling event timer"); > - virEventUpdateTimeout(privst->cbTimer, 0); > - } else { > - VIR_DEBUG("Disabling event timer"); > - virEventUpdateTimeout(privst->cbTimer, -1); > - } > -} > - > - > -static int > -remoteStreamPacket(virStreamPtr st, > - int status, > - const char *data, > - size_t nbytes) > -{ > - VIR_DEBUG("st=%p status=%d data=%p nbytes=%zu", st, status, data, nbytes); > - struct private_data *priv = st->conn->privateData; > - struct private_stream_data *privst = st->privateData; > - XDR xdr; > - struct remote_thread_call *thiscall; > - remote_message_header hdr; > - int ret; > - > - memset(&hdr, 0, sizeof hdr); > - > - if (VIR_ALLOC(thiscall) < 0) { > - virReportOOMError(); > - return -1; > - } > - > - thiscall->mode = REMOTE_MODE_WAIT_TX; > - thiscall->serial = privst->serial; > - thiscall->proc_nr = privst->proc_nr; > - if (status == REMOTE_OK || > - status == REMOTE_ERROR) > - thiscall->want_reply = 1; > - > - if (virCondInit(&thiscall->cond) < 0) { > - VIR_FREE(thiscall); > - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", > - _("cannot initialize mutex")); > - return -1; > - } > - > - /* Don't fill in any other fields in 'thiscall' since > - * we're not expecting a reply for this */ > - > - hdr.prog = REMOTE_PROGRAM; > - hdr.vers = REMOTE_PROTOCOL_VERSION; > - hdr.proc = privst->proc_nr; > - hdr.type = REMOTE_STREAM; > - hdr.serial = privst->serial; > - hdr.status = status; > - > - > - /* Length must include the length word itself (always encoded in > - * 4 bytes as per RFC 4506), so offset start length. We write this > - * later. > - */ > - thiscall->bufferLength = REMOTE_MESSAGE_HEADER_XDR_LEN; > - > - /* Serialise header followed by args. */ > - xdrmem_create (&xdr, thiscall->buffer + thiscall->bufferLength, > - REMOTE_MESSAGE_MAX, XDR_ENCODE); > - if (!xdr_remote_message_header (&xdr, &hdr)) { > - remoteError(VIR_ERR_RPC, "%s", _("xdr_remote_message_header failed")); > - goto error; > - } > - > - thiscall->bufferLength += xdr_getpos (&xdr); > - xdr_destroy (&xdr); > - > - if (status == REMOTE_CONTINUE) { > - if (((4 + REMOTE_MESSAGE_MAX) - thiscall->bufferLength) < nbytes) { > - remoteError(VIR_ERR_RPC, _("data size %zu too large for payload %d"), > - nbytes, ((4 + REMOTE_MESSAGE_MAX) - thiscall->bufferLength)); > - goto error; > - } > - > - memcpy(thiscall->buffer + thiscall->bufferLength, data, nbytes); > - thiscall->bufferLength += nbytes; > - } > - > - /* Go back to packet start and encode the length word. */ > - xdrmem_create (&xdr, thiscall->buffer, REMOTE_MESSAGE_HEADER_XDR_LEN, XDR_ENCODE); > - if (!xdr_u_int (&xdr, &thiscall->bufferLength)) { > - remoteError(VIR_ERR_RPC, "%s", _("xdr_u_int (length word)")); > - goto error; > - } > - xdr_destroy (&xdr); > - > - ret = remoteIO(st->conn, priv, 0, thiscall); > - ignore_value(virCondDestroy(&thiscall->cond)); > - VIR_FREE(thiscall); > - if (ret < 0) > - return -1; > - > - return nbytes; > - > -error: > - xdr_destroy (&xdr); > - ignore_value(virCondDestroy(&thiscall->cond)); > - VIR_FREE(thiscall); > - return -1; > -} > - > -static int > -remoteStreamHasError(virStreamPtr st) { > - struct private_stream_data *privst = st->privateData; > - if (!privst->has_error) { > - return 0; > - } > - > - VIR_DEBUG("Raising async error"); > - virRaiseErrorFull(__FILE__, __FUNCTION__, __LINE__, > - privst->err.domain, > - privst->err.code, > - privst->err.level, > - privst->err.str1 ? *privst->err.str1 : NULL, > - privst->err.str2 ? *privst->err.str2 : NULL, > - privst->err.str3 ? *privst->err.str3 : NULL, > - privst->err.int1, > - privst->err.int2, > - "%s", privst->err.message ? *privst->err.message : NULL); > - > - return 1; > -} > - > -static void > -remoteStreamRelease(virStreamPtr st) > -{ > - struct private_data *priv = st->conn->privateData; > - struct private_stream_data *privst = st->privateData; > - > - if (priv->streams == privst) > - priv->streams = privst->next; > - else { > - struct private_stream_data *tmp = priv->streams; > - while (tmp && tmp->next) { > - if (tmp->next == privst) { > - tmp->next = privst->next; > - break; > - } > - } > - } > - > - if (privst->has_error) > - xdr_free((xdrproc_t)xdr_remote_error, (char *)&privst->err); > - > - VIR_FREE(privst); > - > - st->driver = NULL; > - st->privateData = NULL; > -} > - > > static int > remoteStreamSend(virStreamPtr st, > @@ -4217,22 +3200,21 @@ remoteStreamSend(virStreamPtr st, > { > VIR_DEBUG("st=%p data=%p nbytes=%zu", st, data, nbytes); > struct private_data *priv = st->conn->privateData; > + virNetClientStreamPtr privst = st->privateData; > int rv = -1; > > remoteDriverLock(priv); > > - if (remoteStreamHasError(st)) > + if (virNetClientStreamRaiseError(privst)) > goto cleanup; > > - rv = remoteStreamPacket(st, > - REMOTE_CONTINUE, > - data, > - nbytes); > + rv = virNetClientStreamSendPacket(privst, > + priv->client, > + VIR_NET_CONTINUE, > + data, > + nbytes); > > cleanup: > - if (rv == -1) > - remoteStreamRelease(st); > - > remoteDriverUnlock(priv); > > return rv; > @@ -4246,123 +3228,57 @@ remoteStreamRecv(virStreamPtr st, > { > VIR_DEBUG("st=%p data=%p nbytes=%zu", st, data, nbytes); > struct private_data *priv = st->conn->privateData; > - struct private_stream_data *privst = st->privateData; > + virNetClientStreamPtr privst = st->privateData; > int rv = -1; > > remoteDriverLock(priv); > > - if (remoteStreamHasError(st)) > + if (virNetClientStreamRaiseError(privst)) > goto cleanup; > > - if (!privst->incomingOffset) { > - struct remote_thread_call *thiscall; > - int ret; > - > - if (st->flags & VIR_STREAM_NONBLOCK) { > - VIR_DEBUG("Non-blocking mode and no data available"); > - rv = -2; > - goto cleanup; > - } > - > - if (VIR_ALLOC(thiscall) < 0) { > - virReportOOMError(); > - goto cleanup; > - } > - > - /* We're not really doing an RPC calls, so we're > - * skipping straight to RX part */ > - thiscall->mode = REMOTE_MODE_WAIT_RX; > - thiscall->serial = privst->serial; > - thiscall->proc_nr = privst->proc_nr; > - thiscall->want_reply = 1; > - > - if (virCondInit(&thiscall->cond) < 0) { > - VIR_FREE(thiscall); > - remoteError(VIR_ERR_INTERNAL_ERROR, "%s", > - _("cannot initialize mutex")); > - goto cleanup; > - } > - > - ret = remoteIO(st->conn, priv, 0, thiscall); > - ignore_value(virCondDestroy(&thiscall->cond)); > - VIR_FREE(thiscall); > - if (ret < 0) > - goto cleanup; > - } > - > - VIR_DEBUG("After IO %d", privst->incomingOffset); > - if (privst->incomingOffset) { > - int want = privst->incomingOffset; > - if (want > nbytes) > - want = nbytes; > - memcpy(data, privst->incoming, want); > - if (want < privst->incomingOffset) { > - memmove(privst->incoming, privst->incoming + want, privst->incomingOffset - want); > - privst->incomingOffset -= want; > - } else { > - VIR_FREE(privst->incoming); > - privst->incomingOffset = privst->incomingLength = 0; > - } > - rv = want; > - } else { > - rv = 0; > - } > - > - remoteStreamEventTimerUpdate(privst); > + rv = virNetClientStreamRecvPacket(privst, > + priv->client, > + data, > + nbytes, > + (st->flags & VIR_STREAM_NONBLOCK)); > > VIR_DEBUG("Done %d", rv); > > cleanup: > - if (rv == -1) > - remoteStreamRelease(st); > remoteDriverUnlock(priv); > > return rv; > } > > +struct remoteStreamCallbackData { > + virStreamPtr st; > + virStreamEventCallback cb; > + void *opaque; > + virFreeCallback ff; > +}; > > -static void > -remoteStreamEventTimer(int timer ATTRIBUTE_UNUSED, void *opaque) > +static void remoteStreamEventCallback(virNetClientStreamPtr stream ATTRIBUTE_UNUSED, > + int events, > + void *opaque) > { > - virStreamPtr st = opaque; > - struct private_data *priv = st->conn->privateData; > - struct private_stream_data *privst = st->privateData; > - int events = 0; > - > - remoteDriverLock(priv); > - > - if (privst->cb && > - (privst->cbEvents & VIR_STREAM_EVENT_READABLE) && > - privst->incomingOffset) > - events |= VIR_STREAM_EVENT_READABLE; > - if (privst->cb && > - (privst->cbEvents & VIR_STREAM_EVENT_WRITABLE)) > - events |= VIR_STREAM_EVENT_WRITABLE; > - VIR_DEBUG("Got Timer dispatch %d %d offset=%d", events, privst->cbEvents, privst->incomingOffset); > - if (events) { > - virStreamEventCallback cb = privst->cb; > - void *cbOpaque = privst->cbOpaque; > - virFreeCallback cbFree = privst->cbFree; > - > - privst->cbDispatch = 1; > - remoteDriverUnlock(priv); > - (cb)(st, events, cbOpaque); > - remoteDriverLock(priv); > - privst->cbDispatch = 0; > - > - if (!privst->cb && cbFree) > - (cbFree)(cbOpaque); > - } > + struct remoteStreamCallbackData *cbdata = opaque; > + struct private_data *priv = cbdata->st->conn->privateData; > > remoteDriverUnlock(priv); > + (cbdata->cb)(cbdata->st, events, cbdata->opaque); > + remoteDriverLock(priv); > } > > > -static void > -remoteStreamEventTimerFree(void *opaque) > +static void remoteStreamCallbackFree(void *opaque) > { > - virStreamPtr st = opaque; > - virUnrefStream(st); > + struct remoteStreamCallbackData *cbdata = opaque; > + > + if (!cbdata->cb && cbdata->ff) > + (cbdata->ff)(cbdata->opaque); > + > + virStreamFree(cbdata->st); > + VIR_FREE(opaque); > } > > > @@ -4374,148 +3290,128 @@ remoteStreamEventAddCallback(virStreamPtr st, > virFreeCallback ff) > { > struct private_data *priv = st->conn->privateData; > - struct private_stream_data *privst = st->privateData; > + virNetClientStreamPtr privst = st->privateData; > int ret = -1; > + struct remoteStreamCallbackData *cbdata; > > - remoteDriverLock(priv); > - > - if (privst->cb) { > - remoteError(VIR_ERR_INTERNAL_ERROR, > - "%s", _("multiple stream callbacks not supported")); > - goto cleanup; > + if (VIR_ALLOC(cbdata) < 0) { > + virReportOOMError(); > + return -1; > } > - > + cbdata->cb = cb; > + cbdata->opaque = opaque; > + cbdata->ff = ff; > + cbdata->st = st; > virStreamRef(st); > - if ((privst->cbTimer = > - virEventAddTimeout(-1, > - remoteStreamEventTimer, > - st, > - remoteStreamEventTimerFree)) < 0) { > - virUnrefStream(st); > - goto cleanup; > - } > > - privst->cb = cb; > - privst->cbOpaque = opaque; > - privst->cbFree = ff; > - privst->cbEvents = events; > - > - remoteStreamEventTimerUpdate(privst); > + remoteDriverLock(priv); > > - ret = 0; > + if ((ret = virNetClientStreamEventAddCallback(privst, > + events, > + remoteStreamEventCallback, > + cbdata, > + remoteStreamCallbackFree)) < 0) { > + VIR_FREE(cbdata); > + goto cleanup; > + } > > cleanup: > remoteDriverUnlock(priv); > return ret; > } > > + > static int > remoteStreamEventUpdateCallback(virStreamPtr st, > int events) > { > struct private_data *priv = st->conn->privateData; > - struct private_stream_data *privst = st->privateData; > + virNetClientStreamPtr privst = st->privateData; > int ret = -1; > > remoteDriverLock(priv); > > - if (!privst->cb) { > - remoteError(VIR_ERR_INTERNAL_ERROR, > - "%s", _("no stream callback registered")); > - goto cleanup; > - } > + ret = virNetClientStreamEventUpdateCallback(privst, events); > > - privst->cbEvents = events; > - > - remoteStreamEventTimerUpdate(privst); > - > - ret = 0; > - > -cleanup: > - remoteDriverUnlock(priv); > - return ret; > -} > + remoteDriverUnlock(priv); > + return ret; > +} > > > static int > remoteStreamEventRemoveCallback(virStreamPtr st) > { > struct private_data *priv = st->conn->privateData; > - struct private_stream_data *privst = st->privateData; > + virNetClientStreamPtr privst = st->privateData; > int ret = -1; > > remoteDriverLock(priv); > > - if (!privst->cb) { > - remoteError(VIR_ERR_INTERNAL_ERROR, > - "%s", _("no stream callback registered")); > - goto cleanup; > - } > - > - if (!privst->cbDispatch && > - privst->cbFree) > - (privst->cbFree)(privst->cbOpaque); > - privst->cb = NULL; > - privst->cbOpaque = NULL; > - privst->cbFree = NULL; > - privst->cbEvents = 0; > - virEventRemoveTimeout(privst->cbTimer); > - > - ret = 0; > + ret = virNetClientStreamEventRemoveCallback(privst); > > -cleanup: > remoteDriverUnlock(priv); > return ret; > } > > + > static int > remoteStreamFinish(virStreamPtr st) > { > struct private_data *priv = st->conn->privateData; > + virNetClientStreamPtr privst = st->privateData; > int ret = -1; > > remoteDriverLock(priv); > > - if (remoteStreamHasError(st)) > + if (virNetClientStreamRaiseError(privst)) > goto cleanup; > > - ret = remoteStreamPacket(st, > - REMOTE_OK, > - NULL, > - 0); > + ret = virNetClientStreamSendPacket(privst, > + priv->client, > + VIR_NET_OK, > + NULL, > + 0); > > cleanup: > - remoteStreamRelease(st); > + virNetClientRemoveStream(priv->client, privst); > + virNetClientStreamFree(privst); > + st->privateData = NULL; > + st->driver = NULL; > > remoteDriverUnlock(priv); > return ret; > } > > + > static int > remoteStreamAbort(virStreamPtr st) > { > struct private_data *priv = st->conn->privateData; > + virNetClientStreamPtr privst = st->privateData; > int ret = -1; > > remoteDriverLock(priv); > > - if (remoteStreamHasError(st)) > + if (virNetClientStreamRaiseError(privst)) > goto cleanup; > > - ret = remoteStreamPacket(st, > - REMOTE_ERROR, > - NULL, > - 0); > + ret = virNetClientStreamSendPacket(privst, > + priv->client, > + VIR_NET_ERROR, > + NULL, > + 0); > > cleanup: > - remoteStreamRelease(st); > + virNetClientRemoveStream(priv->client, privst); > + virNetClientStreamFree(privst); > + st->privateData = NULL; > + st->driver = NULL; > > remoteDriverUnlock(priv); > return ret; > } > > > - > static virStreamDriver remoteStreamDrv = { > .streamRecv = remoteStreamRecv, > .streamSend = remoteStreamSend, > @@ -4526,6 +3422,7 @@ static virStreamDriver remoteStreamDrv = { > .streamRemoveCallback = remoteStreamEventRemoveCallback, > }; > > + > static int remoteDomainEventRegisterAny(virConnectPtr conn, > virDomainPtr dom, > int eventID, > @@ -4620,6 +3517,7 @@ done: > return rv; > } > > + > /*----------------------------------------------------------------------*/ > > static int > @@ -4793,23 +3691,28 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn, > const char *dom_xml) > { > struct private_data *priv = dconn->privateData; > - struct private_stream_data *privst = NULL; > int rv = -1; > remote_domain_migrate_prepare_tunnel3_args args; > remote_domain_migrate_prepare_tunnel3_ret ret; > + virNetClientStreamPtr netst; > > remoteDriverLock(priv); > > memset(&args, 0, sizeof(args)); > memset(&ret, 0, sizeof(ret)); > > - if (!(privst = remoteStreamOpen(st, > - REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3, > - priv->counter))) > + if (!(netst = virNetClientStreamNew(priv->remoteProgram, > + REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL, > + priv->counter))) > goto done; > > + if (virNetClientAddStream(priv->client, netst) < 0) { > + virNetClientStreamFree(netst); > + goto done; > + } > + > st->driver = &remoteStreamDrv; > - st->privateData = privst; > + st->privateData = netst; > > args.cookie_in.cookie_in_val = (char *)cookiein; > args.cookie_in.cookie_in_len = cookieinlen; > @@ -4821,7 +3724,8 @@ remoteDomainMigratePrepareTunnel3(virConnectPtr dconn, > if (call(dconn, priv, 0, REMOTE_PROC_DOMAIN_MIGRATE_PREPARE_TUNNEL3, > (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_args, (char *) &args, > (xdrproc_t) xdr_remote_domain_migrate_prepare_tunnel3_ret, (char *) &ret) == -1) { > - remoteStreamRelease(st); > + virNetClientRemoveStream(priv->client, netst); > + virNetClientStreamFree(netst); > goto done; > } > > @@ -5006,1251 +3910,41 @@ done: > #include "remote_client_bodies.h" > #include "qemu_client_bodies.h" > > - > -/*----------------------------------------------------------------------*/ > - > -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, > - _("Unable to marshal arguments for program %d version %d procedure %d type %d status %d"), > - hdr.prog, hdr.vers, hdr.proc, hdr.type, hdr.status); > - 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); > - ignore_value(virCondDestroy(&rv->cond)); > - 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) { > - int ret, err; > - ret = remoteIOReadBuffer(priv, priv->saslTemporary, > - sizeof(priv->saslTemporary)); > - if (ret < 0) > - return -1; > - if (ret == 0) > - return 0; > - > - err = sasl_decode(priv->saslconn, priv->saslTemporary, 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; > - VIR_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 */ > - VIR_DEBUG("Dispatch event %d %d", hdr.proc, priv->bufferLength); > - 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, > - _("Unable to marshal reply for program %d version %d procedure %d type %d status %d"), > - hdr->prog, hdr->vers, hdr->proc, hdr->type, hdr->status); > - 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, > - _("Unable to marshal error for program %d version %d procedure %d type %d status %d"), > - hdr->prog, hdr->vers, hdr->proc, hdr->type, hdr->status); > - return -1; > - } > - thecall->mode = REMOTE_MODE_ERROR; > - return 0; > - > - default: > - remoteError(VIR_ERR_RPC, _("unknown status (received %x)"), hdr->status); > - return -1; > - } > -} > - > -static int > -processCallDispatchMessage(virConnectPtr conn, struct private_data *priv, > - int in_open, > - remote_message_header *hdr, > - XDR *xdr) { > - virDomainEventPtr event = NULL; > - /* An async message has come in while we were waiting for the > - * response. Process it to pull it off the wire, and try again > - */ > - > - if (in_open) { > - VIR_DEBUG("Ignoring bogus event %d received while in open", hdr->proc); > - return -1; > - } > - > - switch (hdr->proc) { > - case REMOTE_PROC_DOMAIN_EVENT_LIFECYCLE: > - event = remoteDomainReadEventLifecycle(conn, xdr); > - break; > - > - case REMOTE_PROC_DOMAIN_EVENT_REBOOT: > - event = remoteDomainReadEventReboot(conn, xdr); > - break; > - > - case REMOTE_PROC_DOMAIN_EVENT_RTC_CHANGE: > - event = remoteDomainReadEventRTCChange(conn, xdr); > - break; > - > - case REMOTE_PROC_DOMAIN_EVENT_WATCHDOG: > - event = remoteDomainReadEventWatchdog(conn, xdr); > - break; > - > - case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR: > - event = remoteDomainReadEventIOError(conn, xdr); > - break; > - > - case REMOTE_PROC_DOMAIN_EVENT_IO_ERROR_REASON: > - event = remoteDomainReadEventIOErrorReason(conn, xdr); > - break; > - > - case REMOTE_PROC_DOMAIN_EVENT_GRAPHICS: > - event = remoteDomainReadEventGraphics(conn, xdr); > - break; > - > - case REMOTE_PROC_DOMAIN_EVENT_CONTROL_ERROR: > - event = remoteDomainReadEventControlError(conn, xdr); > - break; > - > - default: > - VIR_DEBUG("Unexpected event proc %d", hdr->proc); > - break; > - } > - VIR_DEBUG("Event ready for queue %p %p", event, conn); > - > - if (!event) > - return -1; > - > - remoteDomainEventQueue(priv, event); > - return 0; > -} > - > -static int > -processCallDispatchStream(virConnectPtr conn ATTRIBUTE_UNUSED, > - struct private_data *priv, > - remote_message_header *hdr, > - XDR *xdr) { > - struct private_stream_data *privst; > - struct remote_thread_call *thecall; > - > - /* Try and find a matching stream */ > - privst = priv->streams; > - while (privst && > - privst->serial != hdr->serial && > - privst->proc_nr != hdr->proc) > - privst = privst->next; > - > - if (!privst) { > - VIR_DEBUG("No registered stream matching serial=%d, proc=%d", > - hdr->serial, hdr->proc); > - return -1; > - } > - > - /* See if there's also a (optional) call waiting for this reply */ > - thecall = priv->waitDispatch; > - while (thecall && > - thecall->serial != hdr->serial) > - thecall = thecall->next; > - > - > - /* 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_CONTINUE: { > - int avail = privst->incomingLength - privst->incomingOffset; > - int need = priv->bufferLength - priv->bufferOffset; > - VIR_DEBUG("Got a stream data packet"); > - > - /* XXX flag stream as complete somwhere if need==0 */ > - > - if (need > avail) { > - int extra = need - avail; > - if (VIR_REALLOC_N(privst->incoming, > - privst->incomingLength + extra) < 0) { > - VIR_DEBUG("Out of memory handling stream data"); > - return -1; > - } > - privst->incomingLength += extra; > - } > - > - memcpy(privst->incoming + privst->incomingOffset, > - priv->buffer + priv->bufferOffset, > - priv->bufferLength - priv->bufferOffset); > - privst->incomingOffset += (priv->bufferLength - priv->bufferOffset); > - > - if (thecall && thecall->want_reply) { > - VIR_DEBUG("Got sync data packet offset=%d", privst->incomingOffset); > - thecall->mode = REMOTE_MODE_COMPLETE; > - } else { > - VIR_DEBUG("Got aysnc data packet offset=%d", privst->incomingOffset); > - remoteStreamEventTimerUpdate(privst); > - } > - return 0; > - } > - > - case REMOTE_OK: > - VIR_DEBUG("Got a synchronous confirm"); > - if (!thecall) { > - VIR_DEBUG("Got unexpected stream finish confirmation"); > - return -1; > - } > - thecall->mode = REMOTE_MODE_COMPLETE; > - return 0; > - > - case REMOTE_ERROR: > - if (thecall && thecall->want_reply) { > - VIR_DEBUG("Got a synchronous error"); > - /* Give the error straight to this call */ > - memset (&thecall->err, 0, sizeof thecall->err); > - if (!xdr_remote_error (xdr, &thecall->err)) { > - remoteError(VIR_ERR_RPC, "%s", _("unmarshaling remote_error")); > - return -1; > - } > - thecall->mode = REMOTE_MODE_ERROR; > - } else { > - VIR_DEBUG("Got a asynchronous error"); > - /* No call, so queue the error against the stream */ > - if (privst->has_error) { > - VIR_DEBUG("Got unexpected duplicate stream error"); > - return -1; > - } > - privst->has_error = 1; > - memset (&privst->err, 0, sizeof privst->err); > - if (!xdr_remote_error (xdr, &privst->err)) { > - VIR_DEBUG("Failed to unmarshal error"); > - return -1; > - } > - } > - return 0; > - > - default: > - VIR_WARN("Stream with unexpected serial=%d, proc=%d, status=%d", > - hdr->serial, hdr->proc, hdr->status); > - 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, but we don't want to > - * spin around the loop forever if there are many > - * incoming async events, or replies for other > - * thread's RPC calls. We want to get out & let > - * any other thread take over as soon as we've > - * got our reply. When SASL is active though, we > - * may have read more data off the wire than we > - * initially wanted & cached it in memory. In this > - * case, poll() would not detect that there is more > - * ready todo. > - * > - * So if SASL is active *and* some SASL data is > - * already cached, then we'll process that now, > - * before returning. > - */ > -#if HAVE_SASL > - if (ret == 0 && > - priv->saslconn && > - priv->saslDecoded) > - continue; > -#endif > - 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 > - int timeout = -1; > - > - /* If we have existing SASL decoded data we > - * don't want to sleep in the poll(), just > - * check if any other FDs are also ready > - */ > -#if HAVE_SASL > - if (priv->saslDecoded) > - timeout = 0; > -#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), timeout); > - if (ret < 0 && errno == EAGAIN) > - goto repoll; > - > -#ifdef HAVE_PTHREAD_SIGMASK > - ignore_value(pthread_sigmask(SIG_SETMASK, &oldmask, NULL)); > -#endif > - > - remoteDriverLock(priv); > - > - /* If we have existing SASL decoded data, pretend > - * the socket became readable so we consume it > - */ > -#if HAVE_SASL > - if (priv->saslDecoded) > - fds[0].revents |= POLLIN; > -#endif > - > - if (fds[1].revents) { > - ssize_t s; > - VIR_DEBUG("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... > - */ > - VIR_DEBUG("Waking up sleep %d %p %p", tmp->proc_nr, tmp, priv->waitDispatch); > - virCondSignal(&tmp->cond); > - } else { > - 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; > - VIR_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) { > - VIR_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; > - VIR_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) { > - VIR_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; > - > - VIR_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; > - } > - > - VIR_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; > - } > - > - VIR_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; > - } > - > - VIR_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: > - VIR_DEBUG("All done with our call %d %p %p", thiscall->proc_nr, > - priv->waitDispatch, thiscall); > - if (thiscall->mode == REMOTE_MODE_ERROR) { > - /* Interop for virErrorNumber glitch in 0.8.0, if server is > - * 0.7.1 through 0.7.7; see comments in virterror.h. */ > - switch (thiscall->err.code) { > - case VIR_WAR_NO_NWFILTER: > - /* no way to tell old VIR_WAR_NO_SECRET apart from > - * VIR_WAR_NO_NWFILTER, but both are very similar > - * warnings, so ignore the difference */ > - break; > - case VIR_ERR_INVALID_NWFILTER: > - case VIR_ERR_NO_NWFILTER: > - case VIR_ERR_BUILD_FIREWALL: > - /* server was trying to pass VIR_ERR_INVALID_SECRET, > - * VIR_ERR_NO_SECRET, or VIR_ERR_CONFIG_UNSUPPORTED */ > - if (thiscall->err.domain != VIR_FROM_NWFILTER) > - thiscall->err.code += 4; > - break; > - case VIR_WAR_NO_SECRET: > - if (thiscall->err.domain == VIR_FROM_QEMU) > - thiscall->err.code = VIR_ERR_OPERATION_TIMEOUT; > - break; > - case VIR_ERR_INVALID_SECRET: > - if (thiscall->err.domain == VIR_FROM_XEN) > - thiscall->err.code = VIR_ERR_MIGRATE_PERSIST_FAILED; > - break; > - default: > - /* Nothing to alter. */ > - break; > - } > - > - /* 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(__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(__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) { > - return -1; > - } > + /* 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--; > > - rv = remoteIO(conn, priv, flags, thiscall); > - ignore_value(virCondDestroy(&thiscall->cond)); > - VIR_FREE(thiscall); > 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; > - > - VIR_DEBUG("Event fired %d %d %d %X", watch, fd, event, event); > - > - if (event & (VIR_EVENT_HANDLE_HANGUP | VIR_EVENT_HANDLE_ERROR)) { > - VIR_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) > - VIR_DEBUG("Something went wrong during async message processing"); > - > -done: > - remoteDriverUnlock(priv); > -} > - > static void remoteDomainEventDispatchFunc(virConnectPtr conn, > virDomainEventPtr event, > virConnectDomainEventGenericCallback cb, > @@ -6266,7 +3960,7 @@ static void remoteDomainEventDispatchFunc(virConnectPtr conn, > remoteDriverLock(priv); > } > > -void > +static void > remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque) > { > virConnectPtr conn = opaque; > @@ -6282,7 +3976,7 @@ remoteDomainEventQueueFlush(int timer ATTRIBUTE_UNUSED, void *opaque) > remoteDriverUnlock(priv); > } > > -void > +static void > remoteDomainEventQueue(struct private_data *priv, virDomainEventPtr event) > { > virDomainEventStateQueue(priv->domainEventState, event); > diff --git a/src/rpc/gendispatch.pl b/src/rpc/gendispatch.pl > index 71085d9..d6264b9 100755 > --- a/src/rpc/gendispatch.pl > +++ b/src/rpc/gendispatch.pl > @@ -1326,7 +1326,7 @@ elsif ($opt_k) { > } > > if ($call->{streamflag} ne "none") { > - print " struct private_stream_data *privst = NULL;\n"; > + print " virNetClientStreamPtr netst = NULL;\n"; > } > > print "\n"; > @@ -1334,11 +1334,16 @@ elsif ($opt_k) { > > if ($call->{streamflag} ne "none") { > print "\n"; > - print " if (!(privst = remoteStreamOpen(st, REMOTE_PROC_$call->{UC_NAME}, priv->counter)))\n"; > + print " if (!(netst = virNetClientStreamNew(priv->remoteProgram, REMOTE_PROC_$call->{UC_NAME}, priv->counter)))\n"; > print " goto done;\n"; > print "\n"; > + print " if (virNetClientAddStream(priv->client, netst) < 0) {"; > + print " virNetClientStreamFree(netst);\n"; > + print " goto done;\n"; > + print " }"; > + print "\n"; > print " st->driver = &remoteStreamDrv;\n"; > - print " st->privateData = privst;\n"; > + print " st->privateData = netst;\n"; > } > > if ($call->{ProcName} eq "SupportsFeature") { > @@ -1403,7 +1408,8 @@ elsif ($opt_k) { > print " (xdrproc_t)xdr_$call->{ret}, (char *)$call_ret) == -1) {\n"; > > if ($call->{streamflag} ne "none") { > - print " remoteStreamRelease(st);\n"; > + print " virNetClientRemoveStream(priv->client, netst);\n"; > + print " virNetClientStreamFree(netst);\n"; > } > > print " goto done;\n"; -- Eric Blake eblake@xxxxxxxxxx +1-801-349-2682 Libvirt virtualization library http://libvirt.org
Attachment:
signature.asc
Description: OpenPGP digital signature
-- libvir-list mailing list libvir-list@xxxxxxxxxx https://www.redhat.com/mailman/listinfo/libvir-list