mirror of
https://gitlab.com/libvirt/libvirt.git
synced 2024-08-28 11:31:16 +00:00
Add client side support for FD passing
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
This commit is contained in:
parent
b0f996a6b1
commit
36a9c83de4
@ -1184,6 +1184,10 @@ virFileFdopen;
|
||||
virFileRewrite;
|
||||
|
||||
|
||||
# virnetclient.h
|
||||
virNetClientHasPassFD;
|
||||
|
||||
|
||||
# virnetmessage.h
|
||||
virNetMessageClear;
|
||||
virNetMessageDecodeNumFDs;
|
||||
|
@ -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);
|
||||
|
@ -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;
|
||||
|
@ -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);
|
||||
|
||||
|
@ -22,6 +22,8 @@
|
||||
|
||||
#include <config.h>
|
||||
|
||||
#include <unistd.h>
|
||||
|
||||
#include "virnetclientprogram.h"
|
||||
#include "virnetclient.h"
|
||||
#include "virnetprotocol.h"
|
||||
@ -29,6 +31,8 @@
|
||||
#include "memory.h"
|
||||
#include "virterror_internal.h"
|
||||
#include "logging.h"
|
||||
#include "util.h"
|
||||
#include "virfile.h"
|
||||
|
||||
#define VIR_FROM_THIS VIR_FROM_RPC
|
||||
#define virNetError(code, ...) \
|
||||
@ -267,10 +271,20 @@ 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 (infds)
|
||||
*infds = NULL;
|
||||
if (ninfds)
|
||||
*ninfds = 0;
|
||||
|
||||
if (!(msg = virNetMessageNew(false)))
|
||||
return -1;
|
||||
@ -278,13 +292,38 @@ 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++)
|
||||
msg->fds[i] = -1;
|
||||
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 +334,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 +355,30 @@ 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++)
|
||||
*infds[i] = -1;
|
||||
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;
|
||||
@ -335,5 +399,9 @@ int virNetClientProgramCall(virNetClientProgramPtr prog,
|
||||
|
||||
error:
|
||||
virNetMessageFree(msg);
|
||||
if (infds && ninfds) {
|
||||
for (i = 0 ; i < *ninfds ; i++)
|
||||
VIR_FORCE_CLOSE(*infds[i]);
|
||||
}
|
||||
return -1;
|
||||
}
|
||||
|
@ -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);
|
||||
|
||||
|
Loading…
Reference in New Issue
Block a user