From c298145344e7181827638ea37e28e32a52db6237 Mon Sep 17 00:00:00 2001 From: "Daniel P. Berrange" Date: Thu, 9 Aug 2012 12:54:54 +0100 Subject: [PATCH] Add JSON serialization of virNetSocketPtr objects for process re-exec() Add two new APIs virNetSocketNewPostExecRestart and virNetSocketPreExecRestart which allow a virNetSocketPtr object to be created from a JSON object and saved to a JSON object, for the purpose of re-exec'ing a process. As well as saving the state in JSON format, the second method will disable the O_CLOEXEC flag so that the open file descriptors are preserved across the process re-exec() Since it is not possible to serialize SASL or TLS encryption state, an error will be raised if attempting to perform serialization on non-raw sockets Signed-off-by: Daniel P. Berrange --- src/libvirt_private.syms | 2 + src/rpc/virnetsocket.c | 108 +++++++++++++++++++++++++++++++++++++++ src/rpc/virnetsocket.h | 6 +++ 3 files changed, 116 insertions(+) diff --git a/src/libvirt_private.syms b/src/libvirt_private.syms index 5a11368efa..b0f6c81e1b 100644 --- a/src/libvirt_private.syms +++ b/src/libvirt_private.syms @@ -1667,6 +1667,8 @@ virNetSocketNewConnectUNIX; virNetSocketNewListenFD; virNetSocketNewListenTCP; virNetSocketNewListenUNIX; +virNetSocketNewPostExecRestart; +virNetSocketPreExecRestart; virNetSocketRead; virNetSocketRecvFD; virNetSocketRemoteAddrString; diff --git a/src/rpc/virnetsocket.c b/src/rpc/virnetsocket.c index 6ffa06e5b9..55243b9dec 100644 --- a/src/rpc/virnetsocket.c +++ b/src/rpc/virnetsocket.c @@ -882,6 +882,114 @@ int virNetSocketNewConnectExternal(const char **cmdargv, } +virNetSocketPtr virNetSocketNewPostExecRestart(virJSONValuePtr object) +{ + virSocketAddr localAddr; + virSocketAddr remoteAddr; + int fd, thepid, errfd; + bool isClient; + + if (virJSONValueObjectGetNumberInt(object, "fd", &fd) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing fd data in JSON document")); + return NULL; + } + + if (virJSONValueObjectGetNumberInt(object, "pid", &thepid) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing pid data in JSON document")); + return NULL; + } + + if (virJSONValueObjectGetNumberInt(object, "errfd", &errfd) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing errfd data in JSON document")); + return NULL; + } + if (virJSONValueObjectGetBoolean(object, "isClient", &isClient) < 0) { + virReportError(VIR_ERR_INTERNAL_ERROR, "%s", + _("Missing isClient data in JSON document")); + return NULL; + } + + memset(&localAddr, 0, sizeof(localAddr)); + memset(&remoteAddr, 0, sizeof(remoteAddr)); + + remoteAddr.len = sizeof(remoteAddr.data.stor); + if (getsockname(fd, &remoteAddr.data.sa, &remoteAddr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get peer socket name")); + return NULL; + } + + localAddr.len = sizeof(localAddr.data.stor); + if (getsockname(fd, &localAddr.data.sa, &localAddr.len) < 0) { + virReportSystemError(errno, "%s", _("Unable to get local socket name")); + return NULL; + } + + return virNetSocketNew(&localAddr, &remoteAddr, + isClient, fd, errfd, thepid); +} + + +virJSONValuePtr virNetSocketPreExecRestart(virNetSocketPtr sock) +{ + virJSONValuePtr object = NULL; + + virMutexLock(&sock->lock); + +#if HAVE_SASL + if (sock->saslSession) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Unable to save socket state when SASL session is active")); + goto error; + } +#endif + if (sock->tlsSession) { + virReportError(VIR_ERR_OPERATION_INVALID, "%s", + _("Unable to save socket state when TLS session is active")); + goto error; + } + + if (!(object = virJSONValueNewObject())) + goto error; + + if (virJSONValueObjectAppendNumberInt(object, "fd", sock->fd) < 0) + goto error; + + if (virJSONValueObjectAppendNumberInt(object, "errfd", sock->errfd) < 0) + goto error; + + if (virJSONValueObjectAppendNumberInt(object, "pid", sock->pid) < 0) + goto error; + + if (virJSONValueObjectAppendBoolean(object, "isClient", sock->client) < 0) + goto error; + + if (virSetInherit(sock->fd, true) < 0) { + virReportSystemError(errno, + _("Cannot disable close-on-exec flag on socket %d"), + sock->fd); + goto error; + } + if (sock->errfd != -1 && + virSetInherit(sock->errfd, true) < 0) { + virReportSystemError(errno, + _("Cannot disable close-on-exec flag on pipe %d"), + sock->errfd); + goto error; + } + + virMutexUnlock(&sock->lock); + return object; + +error: + virMutexUnlock(&sock->lock); + virJSONValueFree(object); + return NULL; +} + + void virNetSocketDispose(void *obj) { virNetSocketPtr sock = obj; diff --git a/src/rpc/virnetsocket.h b/src/rpc/virnetsocket.h index 261d923e77..e024640af0 100644 --- a/src/rpc/virnetsocket.h +++ b/src/rpc/virnetsocket.h @@ -31,6 +31,7 @@ # ifdef HAVE_SASL # include "virnetsaslcontext.h" # endif +# include "json.h" typedef struct _virNetSocket virNetSocket; typedef virNetSocket *virNetSocketPtr; @@ -93,6 +94,11 @@ int virNetSocketNewConnectLibSSH2(const char *host, int virNetSocketNewConnectExternal(const char **cmdargv, virNetSocketPtr *addr); + +virNetSocketPtr virNetSocketNewPostExecRestart(virJSONValuePtr object); + +virJSONValuePtr virNetSocketPreExecRestart(virNetSocketPtr sock); + int virNetSocketGetFD(virNetSocketPtr sock); int virNetSocketDupFD(virNetSocketPtr sock, bool cloexec);