From: "Daniel P. Berrange" <berrange(a)redhat.com>
Extend the RPC client code to allow file descriptors to be sent
to the server with calls, and received back with replies.
* src/remote/remote_driver.c: Stub extra args
* src/libvirt_private.syms, src/rpc/virnetclient.c,
src/rpc/virnetclient.h, src/rpc/virnetclientprogram.c,
src/rpc/virnetclientprogram.h: Extend APIs to allow
FD passing
---
src/libvirt_private.syms | 4 +++
src/remote/remote_driver.c | 1 +
src/rpc/virnetclient.c | 25 +++++++++++++++++
src/rpc/virnetclient.h | 2 +
src/rpc/virnetclientprogram.c | 58 +++++++++++++++++++++++++++++++++++++++-
src/rpc/virnetclientprogram.h | 4 +++
6 files changed, 92 insertions(+), 2 deletions(-)
diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms
index 924c2c3..94520eb 100644
--- a/src/libvirt_private.syms
+++ b/src/libvirt_private.syms
@@ -1183,6 +1183,10 @@ virFileFclose;
virFileFdopen;
+# virnetclient.h
+virNetClientHasPassFD;
+
+
# virnetmessage.h
virNetMessageClear;
virNetMessageDecodeNumFDs;
diff --git a/src/remote/remote_driver.c b/src/remote/remote_driver.c
index e98ebd7..382bb42 100644
--- a/src/remote/remote_driver.c
+++ b/src/remote/remote_driver.c
@@ -4152,6 +4152,7 @@ call (virConnectPtr conn ATTRIBUTE_UNUSED,
client,
counter,
proc_nr,
+ 0, NULL, NULL, NULL,
args_filter, args,
ret_filter, ret);
remoteDriverLock(priv);
diff --git a/src/rpc/virnetclient.c b/src/rpc/virnetclient.c
index 085dc8d..2b5f67c 100644
--- a/src/rpc/virnetclient.c
+++ b/src/rpc/virnetclient.c
@@ -258,6 +258,16 @@ int virNetClientDupFD(virNetClientPtr client, bool cloexec)
}
+bool virNetClientHasPassFD(virNetClientPtr client)
+{
+ bool hasPassFD;
+ virNetClientLock(client);
+ hasPassFD = virNetSocketHasPassFD(client->sock);
+ virNetClientUnlock(client);
+ return hasPassFD;
+}
+
+
void virNetClientFree(virNetClientPtr client)
{
int i;
@@ -684,6 +694,7 @@ static int virNetClientCallDispatchStream(virNetClientPtr client)
static int
virNetClientCallDispatch(virNetClientPtr client)
{
+ size_t i;
if (virNetMessageDecodeHeader(&client->msg) < 0)
return -1;
@@ -697,6 +708,15 @@ virNetClientCallDispatch(virNetClientPtr client)
case VIR_NET_REPLY: /* Normal RPC replies */
return virNetClientCallDispatchReply(client);
+ case VIR_NET_REPLY_WITH_FDS: /* Normal RPC replies with FDs */
+ if (virNetMessageDecodeNumFDs(&client->msg) < 0)
+ return -1;
+ for (i = 0 ; i < client->msg.nfds ; i++) {
+ if ((client->msg.fds[i] = virNetSocketRecvFD(client->sock)) < 0)
+ return -1;
+ }
+ return virNetClientCallDispatchReply(client);
+
case VIR_NET_MESSAGE: /* Async notifications */
return virNetClientCallDispatchMessage(client);
@@ -728,6 +748,11 @@ virNetClientIOWriteMessage(virNetClientPtr client,
thecall->msg->bufferOffset += ret;
if (thecall->msg->bufferOffset == thecall->msg->bufferLength) {
+ size_t i;
+ for (i = 0 ; i < thecall->msg->nfds ; i++) {
+ if (virNetSocketSendFD(client->sock, thecall->msg->fds[i]) < 0)
+ return -1;
+ }
thecall->msg->bufferOffset = thecall->msg->bufferLength = 0;
if (thecall->expectReply)
thecall->mode = VIR_NET_CLIENT_MODE_WAIT_RX;
diff --git a/src/rpc/virnetclient.h b/src/rpc/virnetclient.h
index 1fabcfd..fb679e8 100644
--- a/src/rpc/virnetclient.h
+++ b/src/rpc/virnetclient.h
@@ -56,6 +56,8 @@ void virNetClientRef(virNetClientPtr client);
int virNetClientGetFD(virNetClientPtr client);
int virNetClientDupFD(virNetClientPtr client, bool cloexec);
+bool virNetClientHasPassFD(virNetClientPtr client);
+
int virNetClientAddProgram(virNetClientPtr client,
virNetClientProgramPtr prog);
diff --git a/src/rpc/virnetclientprogram.c b/src/rpc/virnetclientprogram.c
index 33fa507..b6c063d 100644
--- a/src/rpc/virnetclientprogram.c
+++ b/src/rpc/virnetclientprogram.c
@@ -22,6 +22,8 @@
#include <config.h>
+#include <unistd.h>
+
#include "virnetclientprogram.h"
#include "virnetclient.h"
#include "virnetprotocol.h"
@@ -29,6 +31,7 @@
#include "memory.h"
#include "virterror_internal.h"
#include "logging.h"
+#include "util.h"
#define VIR_FROM_THIS VIR_FROM_RPC
#define virNetError(code, ...) \
@@ -267,10 +270,15 @@ int virNetClientProgramCall(virNetClientProgramPtr prog,
virNetClientPtr client,
unsigned serial,
int proc,
+ size_t noutfds,
+ int *outfds,
+ size_t *ninfds,
+ int **infds,
xdrproc_t args_filter, void *args,
xdrproc_t ret_filter, void *ret)
{
virNetMessagePtr msg;
+ size_t i;
if (!(msg = virNetMessageNew(false)))
return -1;
@@ -278,13 +286,36 @@ int virNetClientProgramCall(virNetClientProgramPtr prog,
msg->header.prog = prog->program;
msg->header.vers = prog->version;
msg->header.status = VIR_NET_OK;
- msg->header.type = VIR_NET_CALL;
+ msg->header.type = noutfds ? VIR_NET_CALL_WITH_FDS : VIR_NET_CALL;
msg->header.serial = serial;
msg->header.proc = proc;
+ msg->nfds = noutfds;
+ if (VIR_ALLOC_N(msg->fds, msg->nfds) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ for (i = 0 ; i < msg->nfds ; i++) {
+ if ((msg->fds[i] = dup(outfds[i])) < 0) {
+ virReportSystemError(errno,
+ _("Cannot duplicate FD %d"),
+ outfds[i]);
+ goto error;
+ }
+ if (virSetInherit(msg->fds[i], false) < 0) {
+ virReportSystemError(errno,
+ _("Cannot set close-on-exec %d"),
+ msg->fds[i]);
+ goto error;
+ }
+ }
if (virNetMessageEncodeHeader(msg) < 0)
goto error;
+ if (msg->nfds &&
+ virNetMessageEncodeNumFDs(msg) < 0)
+ goto error;
+
if (virNetMessageEncodePayload(msg, args_filter, args) < 0)
goto error;
@@ -295,7 +326,8 @@ int virNetClientProgramCall(virNetClientProgramPtr prog,
* virNetClientSend should have validated the reply,
* but it doesn't hurt to check again.
*/
- if (msg->header.type != VIR_NET_REPLY) {
+ if (msg->header.type != VIR_NET_REPLY &&
+ msg->header.type != VIR_NET_REPLY_WITH_FDS) {
virNetError(VIR_ERR_INTERNAL_ERROR,
_("Unexpected message type %d"), msg->header.type);
goto error;
@@ -315,6 +347,28 @@ int virNetClientProgramCall(virNetClientProgramPtr prog,
switch (msg->header.status) {
case VIR_NET_OK:
+ if (infds && ninfds) {
+ *ninfds = msg->nfds;
+ if (VIR_ALLOC_N(*infds, *ninfds) < 0) {
+ virReportOOMError();
+ goto error;
+ }
+ for (i = 0 ; i < *ninfds ; i++) {
+ if ((*infds[i] = dup(msg->fds[i])) < 0) {
+ virReportSystemError(errno,
+ _("Cannot duplicate FD %d"),
+ msg->fds[i]);
+ goto error;
+ }
+ if (virSetInherit(*infds[i], false) < 0) {
+ virReportSystemError(errno,
+ _("Cannot set close-on-exec %d"),
+ *infds[i]);
+ goto error;
+ }
+ }
+
+ }
if (virNetMessageDecodePayload(msg, ret_filter, ret) < 0)
goto error;
break;
diff --git a/src/rpc/virnetclientprogram.h b/src/rpc/virnetclientprogram.h
index 82ae2c6..14a4c96 100644
--- a/src/rpc/virnetclientprogram.h
+++ b/src/rpc/virnetclientprogram.h
@@ -77,6 +77,10 @@ int virNetClientProgramCall(virNetClientProgramPtr prog,
virNetClientPtr client,
unsigned serial,
int proc,
+ size_t noutfds,
+ int *outfds,
+ size_t *ninfds,
+ int **infds,
xdrproc_t args_filter, void *args,
xdrproc_t ret_filter, void *ret);
--
1.7.6.4