diff --git a/examples/systemtap/rpc-monitor.stp b/examples/systemtap/rpc-monitor.stp index f246571771..69d7593a3c 100755 --- a/examples/systemtap/rpc-monitor.stp +++ b/examples/systemtap/rpc-monitor.stp @@ -155,3 +155,13 @@ probe libvirt.rpc.server_client_free { delete serverSocks[pid(), client]; } } + + +probe libvirt.rpc.socket_send_fd { + print_ts(sprintf("= %-16p send fd=%d", sock, fd)); +} + + +probe libvirt.rpc.socket_recv_fd { + print_ts(sprintf("= %-16p recv fd=%d", sock, fd)); +} diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index ad1ef1699b..3b4b429cc9 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1253,9 +1253,13 @@ virNetServerProgramSendStreamError; virNetSocketDupFD; virNetSocketFree; virNetSocketGetFD; +virNetSocketHasPassFD; +virNetSocketIsLocal; virNetSocketListen; virNetSocketNewConnectTCP; virNetSocketNewListenUNIX; +virNetSocketRecvFD; +virNetSocketSendFD; # virnettlscontext.h diff --git a/src/probes.d b/src/probes.d index 7f66ac0594..d0e0b86f4a 100644 --- a/src/probes.d +++ b/src/probes.d @@ -19,6 +19,8 @@ provider libvirt { # file: src/rpc/virnetsocket.c # prefix: rpc probe rpc_socket_new(void *sock, int refs, int fd, int errfd, int pid, const char *localAddr, const char *remoteAddr); + probe rpc_socket_send_fd(void *sock, int fd); + probe rpc_socket_recv_fd(void *sock, int fd); probe rpc_socket_ref(void *sock, int refs); probe rpc_socket_free(void *sock, int refs); diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index e4eff49013..ab88e19fd9 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -43,6 +43,8 @@ #include "event.h" #include "threads.h" +#include "passfd.h" + #define VIR_FROM_THIS VIR_FROM_RPC #define virNetError(code, ...) \ @@ -791,6 +793,17 @@ bool virNetSocketIsLocal(virNetSocketPtr sock) } +bool virNetSocketHasPassFD(virNetSocketPtr sock) +{ + bool hasPassFD = false; + virMutexLock(&sock->lock); + if (sock->localAddr.data.sa.sa_family == AF_UNIX) + hasPassFD = true; + virMutexUnlock(&sock->lock); + return hasPassFD; +} + + int virNetSocketGetPort(virNetSocketPtr sock) { int port; @@ -1128,6 +1141,55 @@ ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len) } +int virNetSocketSendFD(virNetSocketPtr sock, int fd) +{ + int ret = -1; + if (!virNetSocketHasPassFD(sock)) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Sending file descriptors is not supported on this socket")); + return -1; + } + virMutexLock(&sock->lock); + PROBE(RPC_SOCKET_SEND_FD, + "sock=%p fd=%d", sock, fd); + if (sendfd(sock->fd, fd) < 0) { + virReportSystemError(errno, + _("Failed to send file descriptor %d"), + fd); + goto cleanup; + } + ret = 0; + +cleanup: + virMutexUnlock(&sock->lock); + return ret; +} + + +int virNetSocketRecvFD(virNetSocketPtr sock) +{ + int ret = -1; + if (!virNetSocketHasPassFD(sock)) { + virNetError(VIR_ERR_INTERNAL_ERROR, + _("Receiving file descriptors is not supported on this socket")); + return -1; + } + virMutexLock(&sock->lock); + + if ((ret = recvfd(sock->fd, O_CLOEXEC)) < 0) { + virReportSystemError(errno, "%s", + _("Failed to recv file descriptor")); + goto cleanup; + } + PROBE(RPC_SOCKET_RECV_FD, + "sock=%p fd=%d", sock, ret); + +cleanup: + virMutexUnlock(&sock->lock); + return ret; +} + + int virNetSocketListen(virNetSocketPtr sock, int backlog) { virMutexLock(&sock->lock); diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h index 9c4f11251b..13cbb14ddf 100644 --- a/src/rpc/virnetsocket.h +++ b/src/rpc/virnetsocket.h @@ -82,6 +82,8 @@ int virNetSocketDupFD(virNetSocketPtr sock, bool cloexec); bool virNetSocketIsLocal(virNetSocketPtr sock); +bool virNetSocketHasPassFD(virNetSocketPtr sock); + int virNetSocketGetPort(virNetSocketPtr sock); int virNetSocketGetLocalIdentity(virNetSocketPtr sock, @@ -94,6 +96,9 @@ int virNetSocketSetBlocking(virNetSocketPtr sock, ssize_t virNetSocketRead(virNetSocketPtr sock, char *buf, size_t len); ssize_t virNetSocketWrite(virNetSocketPtr sock, const char *buf, size_t len); +int virNetSocketSendFD(virNetSocketPtr sock, int fd); +int virNetSocketRecvFD(virNetSocketPtr sock); + void virNetSocketSetTLSSession(virNetSocketPtr sock, virNetTLSSessionPtr sess); # ifdef HAVE_SASL