static gboolean ToolsCoreRpcCapReg(RpcInData *data) { char *confPath = GuestApp_GetConfPath(); gchar *msg; GArray *pcaps = NULL; ToolsServiceState *state = data->clientData; g_signal_emit_by_name(state->ctx.serviceObj, TOOLS_CORE_SIG_CAPABILITIES, &state->ctx, TRUE, &pcaps); if (pcaps != NULL) { ToolsCore_SetCapabilities(state->ctx.rpc, pcaps, TRUE); g_array_free(pcaps, TRUE); } /* Tell the host the location of the conf directory. */ msg = g_strdup_printf("tools.capability.guest_conf_directory %s", confPath); if (!RpcChannel_Send(state->ctx.rpc, msg, strlen(msg) + 1, NULL, NULL)) { g_debug("Unable to register guest conf directory capability.\n"); } g_free(msg); msg = NULL; /* Send the tools version to the VMX. */ if (state->mainService) { uint32 version; char *result = NULL; size_t resultLen; gchar *toolsVersion; #if defined(OPEN_VM_TOOLS) version = TOOLS_VERSION_UNMANAGED; #else gboolean disableVersion; disableVersion = g_key_file_get_boolean(state->ctx.config, "vmtools", CONFNAME_DISABLETOOLSVERSION, NULL); version = disableVersion ? TOOLS_VERSION_UNMANAGED : TOOLS_VERSION_CURRENT; #endif toolsVersion = g_strdup_printf("tools.set.version %u", version); if (!RpcChannel_Send(state->ctx.rpc, toolsVersion, strlen(toolsVersion) + 1, &result, &resultLen)) { g_debug("Error setting tools version: %s.\n", result); } vm_free(result); g_free(toolsVersion); } state->capsRegistered = TRUE; free(confPath); return RPCIN_SETRETVALS(data, "", TRUE); }
Bool VmBackup_SendEvent(const char *event, const uint32 code, const char *desc) { Bool success; char *result; size_t resultLen; gchar *msg; ASSERT(gBackupState != NULL); g_debug("*** %s\n", __FUNCTION__); if (gBackupState->keepAlive != NULL) { g_source_destroy(gBackupState->keepAlive); g_source_unref(gBackupState->keepAlive); } msg = g_strdup_printf(VMBACKUP_PROTOCOL_EVENT_SET" %s %u %s", event, code, desc); success = RpcChannel_Send(gBackupState->ctx->rpc, msg, strlen(msg) + 1, &result, &resultLen); if (!success) { g_warning("Failed to send event to the VMX: %s.\n", result); } gBackupState->keepAlive = g_timeout_source_new(VMBACKUP_KEEP_ALIVE_PERIOD / 2); VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx, gBackupState->keepAlive, VmBackupKeepAliveCallback, NULL, NULL); return success; }
static Bool VmBackupPrivSendMsg(gchar *msg, char **result, size_t *resultLen) { Bool success; unsigned int oldLevel; ASSERT(gBackupState != NULL); g_debug("*** %s\n", __FUNCTION__); oldLevel = Iopl_Get(); g_debug("Raising the IOPL, oldLevel=%u\n", oldLevel); if (iopl(3) < 0) { g_warning("Error raising the IOPL, %s\n", strerror(errno)); } success = RpcChannel_Send(gBackupState->ctx->rpc, msg, strlen(msg) + 1, result, resultLen); if (iopl(oldLevel) < 0) { g_warning("Error restoring the IOPL, %s\n", strerror(errno)); } return success; }
static void ToolsCoreCheckReset(struct RpcChannel *chan, gboolean success, gpointer _state) { ToolsServiceState *state = _state; ASSERT(state != NULL); if (success) { const gchar *app; gchar *msg; app = ToolsCore_GetTcloName(state); if (app == NULL) { app = state->name; } msg = g_strdup_printf("vmx.capability.unified_loop %s", app); if (!RpcChannel_Send(state->ctx.rpc, msg, strlen(msg) + 1, NULL, NULL)) { g_warning("VMX doesn't support the Tools unified loop.\n" "Some functionality (like setting options) may not work.\n"); } g_free(msg); /* * Log the Tools build number to the VMX log file. We don't really care * if sending the message fails. */ msg = g_strdup_printf("log %s: Version: %s", app, BUILD_NUMBER); RpcChannel_Send(state->ctx.rpc, msg, strlen(msg) + 1, NULL, NULL); g_free(msg); g_signal_emit_by_name(state->ctx.serviceObj, TOOLS_CORE_SIG_RESET, &state->ctx); } else { VMTOOLSAPP_ERROR(&state->ctx, EXIT_FAILURE); } }
gboolean RpcChannel_SendOneRaw(const char *data, size_t dataLen, char **result, size_t *resultLen) { RpcChannel *chan; gboolean status; status = FALSE; chan = RpcChannel_New(); if (chan == NULL) { if (result != NULL) { *result = Util_SafeStrdup("RpcChannel: Unable to create " "the RpcChannel object"); if (resultLen != NULL) { *resultLen = strlen(*result); } } goto sent; } else if (!RpcChannel_Start(chan)) { if (result != NULL) { *result = Util_SafeStrdup("RpcChannel: Unable to open the " "communication channel"); if (resultLen != NULL) { *resultLen = strlen(*result); } } goto sent; } else if (!RpcChannel_Send(chan, data, dataLen, result, resultLen)) { /* We already have the description of the error */ goto sent; } status = TRUE; sent: Debug(LGPFX "Request %s: reqlen=%"FMTSZ"u, replyLen=%"FMTSZ"u\n", status ? "OK" : "FAILED", dataLen, resultLen ? *resultLen : 0); if (chan) { RpcChannel_Stop(chan); RpcChannel_Destroy(chan); } return status; }
static void PowerOpsStateChangeDone(PowerOpState *state, gboolean success) { gchar *msg; g_debug("State change complete, success = %d.\n", success); /* * We execute the requested action if the script succeeded, or if the * same action was tried before but didn't finish due to a script failure. * See bug 168568 for discussion. */ if (success || state->lastFailedStateChg == state->stateChgInProgress) { success = TRUE; state->lastFailedStateChg = GUESTOS_STATECHANGE_NONE; } if (!success) { state->lastFailedStateChg = state->stateChgInProgress; } /* Send the status message to the VMX. */ msg = g_strdup_printf("tools.os.statechange.status %d %d", success, state->stateChgInProgress); if (!RpcChannel_Send(state->ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) { g_warning("Unable to send the status RPC."); } g_free(msg); /* Finally, perform the requested operation. */ if (success) { if (state->stateChgInProgress == GUESTOS_STATECHANGE_REBOOT) { g_message("Initiating reboot.\n"); System_Shutdown(TRUE); } else if (state->stateChgInProgress == GUESTOS_STATECHANGE_HALT) { g_message("Initiating halt.\n"); System_Shutdown(FALSE); } } state->stateChgInProgress = GUESTOS_STATECHANGE_NONE; }
static void ResolutionSetServerCapability(RpcChannel *chan, unsigned int value) { gchar *msg; if (!rpcChannelName) { g_debug("Channel name is null, RPC not sent.\n"); return; } msg = g_strdup_printf("tools.capability.resolution_server %s %d", rpcChannelName, value); if (!RpcChannel_Send(chan, msg, strlen(msg), NULL, NULL)) { g_warning("%s: Unable to set tools.capability.resolution_server\n", __FUNCTION__); } g_free(msg); }
void CopyPasteDnDWrapper::OnResetInternal() { g_debug("%s: enter\n", __FUNCTION__); /* * Reset DnD/Copy/Paste only if vmx said we can. The reason is that * we may also get reset request from vmx when user is taking snapshot * or recording. If there is an ongoing DnD/copy/paste, we should not * reset here. For details please refer to bug 375928. */ char *reply = NULL; size_t replyLen; ToolsAppCtx *ctx = GetToolsAppCtx(); if (RpcChannel_Send(ctx->rpc, "dnd.is.active", strlen("dnd.is.active"), &reply, &replyLen) && (1 == atoi(reply))) { g_debug("%s: ignore reset while file transfer is busy.\n", __FUNCTION__); goto exit; } if (IsDnDRegistered()) { UnregisterDnD(); } if (IsCPRegistered()) { UnregisterCP(); } if (IsCPEnabled() && !IsCPRegistered()) { RegisterCP(); } if (IsDnDEnabled() && !IsDnDRegistered()) { RegisterDnD(); } if (!IsDnDRegistered() || !IsCPRegistered()) { g_debug("%s: unable to reset fully DnD %d CP %d!\n", __FUNCTION__, IsDnDRegistered(), IsCPRegistered()); } exit: free(reply); }
gboolean ToolsCmd_SendRPC(const char *rpc, // IN size_t rpcLen, // IN char **result, // OUT size_t *resultLen) // OUT { char *lrpc = (char *) rpc; RpcChannel *chan = BackdoorChannel_New(); gboolean ret = RpcChannel_Start(chan); if (!ret) { g_warning("Error starting RPC channel."); goto exit; } ret = RpcChannel_Send(chan, lrpc, rpcLen, result, resultLen); exit: RpcChannel_Destroy(chan); return ret; }
int CopyPasteDnDWrapper::GetDnDVersion() { g_debug("%s: enter\n", __FUNCTION__); if (IsDnDRegistered()) { char *reply = NULL; size_t replyLen; ToolsAppCtx *ctx = GetToolsAppCtx(); if (!RpcChannel_Send(ctx->rpc, QUERY_VMX_DND_VERSION, strlen(QUERY_VMX_DND_VERSION), &reply, &replyLen)) { g_debug("%s: could not get VMX dnd " "version capability: %s\n", __FUNCTION__, reply ? reply : "NULL"); m_dndVersion = 1; } else { m_dndVersion = atoi(reply); } free(reply); } g_debug("%s: got version %d\n", __FUNCTION__, m_dndVersion); return m_dndVersion; }
static GArray * HgfsServerCapReg(gpointer src, ToolsAppCtx *ctx, gboolean set, ToolsPluginData *plugin) { gchar *msg; const char *appName = NULL; if (strcmp(ctx->name, VMTOOLS_GUEST_SERVICE) == 0) { appName = TOOLS_DAEMON_NAME; } else if (strcmp(ctx->name, VMTOOLS_USER_SERVICE) == 0) { appName = TOOLS_DND_NAME; } else { NOT_REACHED(); } msg = g_strdup_printf("tools.capability.hgfs_server %s %d", appName, set ? 1 : 0); /* * Prior to WS55, the VMX did not know about the "hgfs_server" * capability. This doesn't mean that the HGFS server wasn't needed, it's * just that the capability was introduced in CS 225439 so that the VMX * could decide which HGFS server to communicate with. * * Long story short, we shouldn't care if this function fails. */ if (ctx->rpc && !RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL)) { g_warning("Setting HGFS server capability failed!\n"); } g_free(msg); return NULL; }
void ToolsDaemonTcloReportProgramCompleted(const char *requestName, // IN VixError err, // IN int exitCode, // IN int64 pid, // IN void *clientData) // IN { Bool sentResult; ToolsAppCtx *ctx = clientData; gchar *msg = g_strdup_printf("%s %s %"FMT64"d %d %d %"FMT64"d", VIX_BACKDOORCOMMAND_RUN_PROGRAM_DONE, requestName, err, Err_Errno(), exitCode, (int64) pid); sentResult = RpcChannel_Send(ctx->rpc, msg, strlen(msg) + 1, NULL, NULL); g_free(msg); if (!sentResult) { Warning("Unable to send results from polling the result program.\n\n"); } } // ToolsDaemonTcloReportProgramCompleted
void CopyPasteDnDWrapper::OnCapReg(gboolean set) { g_debug("%s: enter\n", __FUNCTION__); char *reply = NULL; size_t replyLen; const char *toolsDnDVersion = TOOLS_DND_VERSION_4; char *toolsCopyPasteVersion = NULL; int version; ToolsAppCtx *ctx = GetToolsAppCtx(); if (ctx) { /* * First DnD. */ if (!RpcChannel_Send(ctx->rpc, toolsDnDVersion, strlen(toolsDnDVersion), NULL, NULL)) { g_debug("%s: could not set guest dnd version capability\n", __FUNCTION__); version = 1; SetDnDVersion(version); } else { char const *vmxDnDVersion = QUERY_VMX_DND_VERSION; if (!RpcChannel_Send(ctx->rpc, vmxDnDVersion, strlen(vmxDnDVersion), &reply, &replyLen)) { g_debug("%s: could not get VMX dnd version capability, assuming v1\n", __FUNCTION__); version = 1; SetDnDVersion(version); } else { int version = atoi(reply); ASSERT(version >= 1); SetDnDVersion(version); g_debug("%s: VMX is dnd version %d\n", __FUNCTION__, GetDnDVersion()); if (version == 3) { /* * VMDB still has version 4 in it, which will cause a V3 * host to fail. So, change to version 3. Since we don't * support any other version, we only do this for V3. */ toolsDnDVersion = TOOLS_DND_VERSION_3; if (!RpcChannel_Send(ctx->rpc, toolsDnDVersion, strlen(toolsDnDVersion), NULL, NULL)) { g_debug("%s: could not set VMX dnd version capability, assuming v1\n", __FUNCTION__); version = 1; SetDnDVersion(version); } } } vm_free(reply); reply = NULL; } /* * Now CopyPaste. */ toolsCopyPasteVersion = g_strdup_printf(TOOLS_COPYPASTE_VERSION" %d", 4); if (!RpcChannel_Send(ctx->rpc, toolsCopyPasteVersion, strlen(toolsCopyPasteVersion), NULL, NULL)) { g_debug("%s: could not set guest copypaste version capability\n", __FUNCTION__); version = 1; SetCPVersion(version); } else { char const *vmxCopyPasteVersion = QUERY_VMX_COPYPASTE_VERSION; if (!RpcChannel_Send(ctx->rpc, vmxCopyPasteVersion, strlen(vmxCopyPasteVersion), &reply, &replyLen)) { g_debug("%s: could not get VMX copypaste version capability, assuming v1\n", __FUNCTION__); version = 1; SetCPVersion(version); } else { version = atoi(reply); ASSERT(version >= 1); SetCPVersion(version); g_debug("%s: VMX is copypaste version %d\n", __FUNCTION__, GetCPVersion()); if (version == 3) { /* * VMDB still has version 4 in it, which will cause a V3 * host to fail. So, change to version 3. Since we don't * support any other version, we only do this for V3. */ g_free(toolsCopyPasteVersion); toolsCopyPasteVersion = g_strdup_printf(TOOLS_COPYPASTE_VERSION" %d", 3); if (!RpcChannel_Send(ctx->rpc, toolsCopyPasteVersion, strlen(toolsCopyPasteVersion), NULL, NULL)) { g_debug("%s: could not set VMX copypaste version, assuming v1\n", __FUNCTION__); version = 1; SetCPVersion(version); } } } vm_free(reply); } g_free(toolsCopyPasteVersion); } }
DnDCPTransportGuestRpc::DnDCPTransportGuestRpc(RpcChannel *chan) : mRpcChannel(chan) #else DnDCPTransportGuestRpc::DnDCPTransportGuestRpc(void) #endif { for (int i = 0; i < TRANSPORT_INTERFACE_MAX; i++) { mCBCtx[i].transport = this; mCBCtx[i].type = (TransportInterfaceType)i; } } /** * Register a rpc callback to an interface. * * @param[in] rpc rpc which is listening to the message. * @param[in] type the interface type rpc is listening to. * * @return true on success, false otherwise. */ bool DnDCPTransportGuestRpc::RegisterRpc(RpcBase *rpc, TransportInterfaceType type) { if (mTables.GetRpc(type)) { LOG(0, ("%s: the type %d is already registered\n", __FUNCTION__, type)); UnregisterRpc(type); } const char *cmdStr = (const char *)mTables.GetCmdStr(type); const char *disableStr = mTables.GetDisableStr(type); if (!cmdStr || !disableStr) { LOG(0, ("%s: can not find valid cmd for %d, cmdStr %s disableStr %s\n", __FUNCTION__, type, (cmdStr ? cmdStr : "NULL"), (disableStr ? disableStr : "NULL"))); return false; } ASSERT(mCBCtx); ASSERT(type == TRANSPORT_GUEST_CONTROLLER_DND || type == TRANSPORT_GUEST_CONTROLLER_CP || type == TRANSPORT_GUEST_CONTROLLER_FT); LOG(4, ("%s: for %s\n", __FUNCTION__, cmdStr)); #ifdef VMX86_TOOLS ASSERT(mRpcChannel); mRpcChanCBList[type].name = cmdStr; mRpcChanCBList[type].callback = RecvMsgCB; mRpcChanCBList[type].clientData = &mCBCtx[type]; mRpcChanCBList[type].xdrIn = NULL; mRpcChanCBList[type].xdrOut = NULL; mRpcChanCBList[type].xdrInSize = 0; RpcChannel_RegisterCallback(mRpcChannel, &mRpcChanCBList[type]); #else GuestRpc_RegisterCommand(mTables.GetCmd(type), disableStr, (const unsigned char *)cmdStr, RecvMsgCB, &mCBCtx[type]); #endif mTables.SetRpc(type, rpc); return true; } /** * Unregister a rpc callback. * * @param[in] type the interface type rpc is listening to. * * @return true on success, false otherwise. */ bool DnDCPTransportGuestRpc::UnregisterRpc(TransportInterfaceType type) { if (!mTables.GetRpc(type)) { LOG(0, ("%s: the type %d is not registered\n", __FUNCTION__, type)); return false; } #ifdef VMX86_TOOLS ASSERT(mRpcChannel); RpcChannel_UnregisterCallback(mRpcChannel, &mRpcChanCBList[type]); #else GuestRpc_UnregisterCommand(mTables.GetCmd(type)); #endif mTables.SetRpc(type, NULL); return true; } /** * Wrap the buffer into an rpc and send it to the peer. * * @param[ignored] destId destination address id * @param[in] type transport interface type * @param[in] data Payload buffer * @param[in] dataSize Payload buffer size * * @return true on success, false otherwise. */ bool DnDCPTransportGuestRpc::SendPacket(uint32 destId, TransportInterfaceType type, const uint8 *msg, size_t length) { char *rpc = NULL; size_t rpcSize = 0; size_t nrWritten = 0; const char *cmd = mTables.GetCmdStr(type); bool ret = true; if (!cmd) { LOG(0, ("%s: can not find valid cmd for %d\n", __FUNCTION__, type)); return false; } rpcSize = strlen(cmd) + 1 + length; rpc = (char *)Util_SafeMalloc(rpcSize); nrWritten = Str_Sprintf(rpc, rpcSize, "%s ", cmd); if (length > 0) { ASSERT(nrWritten + length <= rpcSize); memcpy(rpc + nrWritten, msg, length); } #ifdef VMX86_TOOLS ret = (TRUE == RpcChannel_Send(mRpcChannel, rpc, rpcSize, NULL, NULL)); if (!ret) { LOG(0, ("%s: failed to send msg to host\n", __FUNCTION__)); } free(rpc); #else GuestRpc_SendWithTimeOut((const unsigned char *)TOOLS_DND_NAME, (const unsigned char *)rpc, rpcSize, GuestRpc_GenericCompletionRoutine, rpc, DND_TIMEOUT); #endif return ret; }
Bool VmBackup_SendEvent(const char *event, const uint32 code, const char *desc) { Bool success; char *result = NULL; size_t resultLen; gchar *msg; ASSERT(gBackupState != NULL); g_debug("*** %s\n", __FUNCTION__); if (gBackupState->keepAlive != NULL) { g_source_destroy(gBackupState->keepAlive); g_source_unref(gBackupState->keepAlive); } msg = g_strdup_printf(VMBACKUP_PROTOCOL_EVENT_SET" %s %u %s", event, code, desc); g_debug("Sending vmbackup event: %s\n", msg); #if defined(__linux__) if (gBackupState->needsPriv) { success = VmBackupPrivSendMsg(msg, &result, &resultLen); } else { success = RpcChannel_Send(gBackupState->ctx->rpc, msg, strlen(msg) + 1, &result, &resultLen); if (!success) { const char *privErr = "Guest is not privileged"; if (resultLen > strlen(privErr) && strncmp(result, privErr, strlen(privErr)) == 0) { g_debug("Failed to send event: %s\n", result); vm_free(result); /* * PR1444259: * Some hosts enforce privilege elevation for sending this * event, especially 5.5. This is Linux specific because * version 9.4.x on Linux only triggers host side check for * privilege elevation by sending iopl_elevation capability * to the host. */ gBackupState->needsPriv = TRUE; g_debug("Sending event with priv: %s\n", msg); success = VmBackupPrivSendMsg(msg, &result, &resultLen); } else { gBackupState->needsPriv = FALSE; } } } #else success = RpcChannel_Send(gBackupState->ctx->rpc, msg, strlen(msg) + 1, &result, &resultLen); #endif if (!success) { g_warning("Failed to send vmbackup event: %s.\n", result); } vm_free(result); g_free(msg); gBackupState->keepAlive = g_timeout_source_new(VMBACKUP_KEEP_ALIVE_PERIOD / 2); VMTOOLSAPP_ATTACH_SOURCE(gBackupState->ctx, gBackupState->keepAlive, VmBackupKeepAliveCallback, NULL, NULL); return success; }
void ToolsCore_SetCapabilities(RpcChannel *chan, GArray *caps, gboolean set) { char *result; size_t resultLen; guint i; gchar *newcaps = NULL; for (i = 0; i < caps->len; i++) { gchar *tmp; ToolsAppCapability *cap = &g_array_index(caps, ToolsAppCapability, i); switch (cap->type) { case TOOLS_CAP_OLD: result = NULL; tmp = g_strdup_printf("tools.capability.%s %u", cap->name, set ? cap->value : 0); if (!RpcChannel_Send(chan, tmp, strlen(tmp) + 1, &result, &resultLen)) { g_warning("Error sending capability %s: %s\n", cap->name, result); } vm_free(result); g_free(tmp); break; case TOOLS_CAP_OLD_NOVAL: /* * This is kind of weird, because of the way the VMX treats RPCs and * what is expected of these capabilities without arguments. For a * few details, see the comments in RpcOut_sendOne() (rpcout.c). * Basically, for the VMX handlers not to complain, we need to send the * RPC with the empty space at the end, and not consider the NULL * character when counting the bytes. */ if (set) { tmp = g_strdup_printf("tools.capability.%s ", cap->name); if (!RpcChannel_Send(chan, tmp, strlen(tmp), &result, &resultLen)) { g_warning("Error sending capability %s: %s\n", cap->name, result); } vm_free(result); g_free(tmp); } break; case TOOLS_CAP_NEW: if (newcaps == NULL) { newcaps = g_strdup(GUEST_CAP_FEATURES); } tmp = g_strdup_printf("%s %d=%u", newcaps, cap->index, set ? cap->value : 0); g_free(newcaps); newcaps = tmp; break; default: g_error("Invalid capability type: %d\n", cap->type); } } if (newcaps != NULL) { result = NULL; if (!RpcChannel_Send(chan, newcaps, strlen(newcaps) + 1, &result, &resultLen)) { g_warning("Error sending new-style capabilities: %s\n", result); } vm_free(result); g_free(newcaps); } }