[libvirt] [PATCH 6/8] Add client side support for FD passing

Daniel P. Berrange berrange at redhat.com
Tue Oct 25 16:03:46 UTC 2011


From: "Daniel P. Berrange" <berrange at 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




More information about the libvir-list mailing list