]> git.ipfire.org Git - thirdparty/open-vm-tools.git/commitdiff
[TimeInfo] Subscribe/unsubscribe to notifications during init/shutdown
authorKaty Feng <fkaty@vmware.com>
Fri, 23 Dec 2022 00:25:50 +0000 (16:25 -0800)
committerKaty Feng <fkaty@vmware.com>
Fri, 23 Dec 2022 00:25:50 +0000 (16:25 -0800)
This change adds support for subscribing to time info notifications
when this feature is enabled in the tools. As a result VMX will
send time info notifications to the tools when host timing
properties change. The change adds support to perform subscribe/
unsubscribe GuestRPCs from tools. Note that, handling of notification
(received from VMX) will be implemented in the next change.

open-vm-tools/services/plugins/timeSync/timeInfo.c

index e36311e4d5b6abcb4301fecd2dece8fd5b05a44e..98af375520e958f1536ec7c42faebcf12b1781eb 100644 (file)
 #include "conf.h"
 #include "timeSync.h"
 #include "system.h"
+#include "strutil.h"
+#include "vmware/tools/log.h"
 #include "vmware/tools/plugin.h"
 
+typedef struct TimeInfoVmxRpcCtx {
+   char *request;
+   struct {
+      char *reply;
+      size_t replyLen;
+   } response;
+} TimeInfoVmxRpcCtx;
+
+static const char *TIMEINFO_VMXRPC_CLOCKID         = "precisionclock0";
+static const char *TIMEINFO_VMXRPC_CMD_SUBSCRIBE   = "subscribe";
+static const char *TIMEINFO_VMXRPC_CMD_UNSUBSCRIBE = "unsubscribe";
+static const char *TIMEINFO_VMXRPC_STATUS_OK       = "OK";
+static ToolsAppCtx *gToolsAppCtx;
+
+
+/**
+ * Cleanup routine after performing GuestRPC.
+ *
+ * @param[in] rpc TimeInfo RPC context.
+ */
+
+static void
+TimeInfoVmxRpcDone(TimeInfoVmxRpcCtx *rpc)
+{
+   free(rpc->request);
+   RpcChannel_Free(rpc->response.reply);
+   memset(rpc, 0, sizeof *rpc);
+}
+
+
+/**
+ * Perform given GuestRPC.
+ *
+ * @param[in] rpc    TimeInfo RPC context
+ * @param[in] method GuestRPC method to invoke.
+ * @param[in] argv   List of arguments to GuestRPC
+ * @param[in] argc   Number of arguments to GuestRPC
+ *
+ * @return TRUE on successful invocation of GuestRPC, FALSE otherwise.
+ */
+
+static gboolean
+TimeInfoVmxRpcDo(TimeInfoVmxRpcCtx *rpc,
+                 const char *method,
+                 const char *argv[],
+                 size_t argc)
+{
+   Bool ok;
+   char *next;
+   int i;
+   char *status;
+
+   memset(rpc, 0, sizeof *rpc);
+   StrUtil_SafeStrcatF(&rpc->request, "timeInfo.%s", method);
+   for (i = 0; i < argc; ++i) {
+      StrUtil_SafeStrcatF(&rpc->request, " %s", argv[i]);
+   }
+
+   g_debug("%s: Sending RPC: '%s'", __FUNCTION__, rpc->request);
+   ok = RpcChannel_Send(gToolsAppCtx->rpc, rpc->request,
+                        strlen(rpc->request), &rpc->response.reply,
+                        &rpc->response.replyLen);
+   if (!ok) {
+      g_warning("%s: RpcChannel_Send failed.", __FUNCTION__);
+      return FALSE;
+   }
+
+   if (rpc->response.reply == NULL || rpc->response.replyLen == 0) {
+      g_warning("%s: Empty response received from VMX.", __FUNCTION__);
+      return FALSE;
+   }
+   g_debug("%s: RPC response: %s\n", __FUNCTION__, rpc->response.reply);
+
+   next = rpc->response.reply;
+   status = StrUtil_GetNextItem(&next, '\n');
+
+   /* On success, extract payload. */
+   if (status == NULL ||
+       strcmp(status, TIMEINFO_VMXRPC_STATUS_OK) != 0 || next != NULL) {
+      g_warning("%s: Invalid result payload.", __FUNCTION__);
+      return FALSE;
+   }
+   return TRUE;
+}
+
+
+/**
+ * Subscribe to TimeInfo updates. If successful, VMX will send UPDATE
+ * GuestRPCs to tools when host's time related properties change.
+ */
+
+static void
+TimeInfoVmxSubscribe(void)
+{
+   TimeInfoVmxRpcCtx vmxRpc;
+   const char *argv[1] = { TIMEINFO_VMXRPC_CLOCKID };
+
+   g_debug("%s: Subscribing for notifications from VMX.", __FUNCTION__);
+   if (!TimeInfoVmxRpcDo(&vmxRpc, TIMEINFO_VMXRPC_CMD_SUBSCRIBE,
+                         argv, ARRAYSIZE(argv))) {
+      g_warning("%s: Failed to subscribe with VMX for notifications.",
+                __FUNCTION__);
+   }
+   TimeInfoVmxRpcDone(&vmxRpc);
+}
+
+
+/**
+ * Unsubscribe from TimeInfo updates. If successful, VMX will no longer
+ * send UPDATE GuestRPC to the tools.
+ */
+
+static void
+TimeInfoVmxUnsubscribe(void)
+{
+   TimeInfoVmxRpcCtx vmxRpc;
+   const char *argv[1] = { TIMEINFO_VMXRPC_CLOCKID };
+
+   g_debug("%s: Unsubscribing from notifications from VMX.", __FUNCTION__);
+   if (!TimeInfoVmxRpcDo(&vmxRpc, TIMEINFO_VMXRPC_CMD_UNSUBSCRIBE,
+                         argv, ARRAYSIZE(argv))) {
+      g_warning("%s: Failed to unsubscribe from VMX notifications.",
+                __FUNCTION__);
+   }
+   TimeInfoVmxRpcDone(&vmxRpc);
+}
+
 
 /**
  * Initialize TimeInfo in TimeSync.
  *
  * @param[in] ctx The application context.
  */
+
 void
 TimeInfo_Init(ToolsAppCtx *ctx)
 {
@@ -45,13 +175,22 @@ TimeInfo_Init(ToolsAppCtx *ctx)
    ASSERT(vmx86_linux);
    g_debug("%s: TimeInfo support is %senabled.\n",
            __FUNCTION__, !timeInfoEnabled ? "not " : "");
+   if (timeInfoEnabled) {
+      gToolsAppCtx = ctx;
+      TimeInfoVmxSubscribe();
+   }
 }
 
 
 /**
  * Cleans up internal TimeInfo state.
  */
+
 void
 TimeInfo_Shutdown(void)
 {
+   if (gToolsAppCtx != NULL) {
+      TimeInfoVmxUnsubscribe();
+      gToolsAppCtx = NULL;
+   }
 }