[40498] | 1 | /* $Id: VBoxLA.cpp 99828 2023-05-17 13:48:57Z vboxsync $ */
|
---|
| 2 | /** @file
|
---|
| 3 | * VBoxLA - VBox Location Awareness notifications.
|
---|
| 4 | */
|
---|
| 5 |
|
---|
| 6 | /*
|
---|
[98103] | 7 | * Copyright (C) 2014-2023 Oracle and/or its affiliates.
|
---|
[40498] | 8 | *
|
---|
[96407] | 9 | * This file is part of VirtualBox base platform packages, as
|
---|
| 10 | * available from https://www.virtualbox.org.
|
---|
| 11 | *
|
---|
| 12 | * This program is free software; you can redistribute it and/or
|
---|
| 13 | * modify it under the terms of the GNU General Public License
|
---|
| 14 | * as published by the Free Software Foundation, in version 3 of the
|
---|
| 15 | * License.
|
---|
| 16 | *
|
---|
| 17 | * This program is distributed in the hope that it will be useful, but
|
---|
| 18 | * WITHOUT ANY WARRANTY; without even the implied warranty of
|
---|
| 19 | * MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU
|
---|
| 20 | * General Public License for more details.
|
---|
| 21 | *
|
---|
| 22 | * You should have received a copy of the GNU General Public License
|
---|
| 23 | * along with this program; if not, see <https://www.gnu.org/licenses>.
|
---|
| 24 | *
|
---|
| 25 | * SPDX-License-Identifier: GPL-3.0-only
|
---|
[40498] | 26 | */
|
---|
[69361] | 27 |
|
---|
[40498] | 28 |
|
---|
[95960] | 29 | /*********************************************************************************************************************************
|
---|
| 30 | * Header Files *
|
---|
| 31 | *********************************************************************************************************************************/
|
---|
[40498] | 32 | #include <iprt/assert.h>
|
---|
| 33 | #include <iprt/alloc.h>
|
---|
| 34 | #include <iprt/list.h>
|
---|
[46593] | 35 | #include <iprt/ldr.h>
|
---|
[95961] | 36 | #include <iprt/log.h>
|
---|
[76409] | 37 | #include <iprt/utf16.h>
|
---|
[40498] | 38 |
|
---|
[95960] | 39 | #define _WIN32_WINNT 0x0501
|
---|
| 40 | #include <iprt/win/windows.h>
|
---|
[40498] | 41 |
|
---|
[95960] | 42 | #include "VBoxTray.h"
|
---|
| 43 | #include "VBoxLA.h"
|
---|
[51469] | 44 |
|
---|
| 45 |
|
---|
[95960] | 46 | /*********************************************************************************************************************************
|
---|
| 47 | * Defines *
|
---|
| 48 | *********************************************************************************************************************************/
|
---|
[40498] | 49 | #define REG_KEY_LEN 1024
|
---|
| 50 | #define MAX_CLIENT_NAME_CHARS 1024
|
---|
| 51 |
|
---|
| 52 | #define LA_DO_NOTHING 0
|
---|
| 53 | #define LA_DO_ATTACH 1
|
---|
| 54 | #define LA_DO_DETACH 2
|
---|
| 55 | #define LA_DO_DETACH_AND_ATTACH 3
|
---|
| 56 | #define LA_DO_ATTACH_AND_DETACH 4
|
---|
| 57 |
|
---|
[43584] | 58 |
|
---|
| 59 | #define LA_UTCINFO_CLIENT_NAME 0
|
---|
| 60 | #define LA_UTCINFO_CLIENT_IPADDR 1
|
---|
| 61 | #define LA_UTCINFO_CLIENT_LOCATION 2
|
---|
| 62 | #define LA_UTCINFO_CLIENT_OTHERINFO 3
|
---|
| 63 | #define LA_UTCINFO_CLIENT_INFO_LAST 3
|
---|
| 64 |
|
---|
| 65 | #define LA_UTCINFO_PROP_NAME 0
|
---|
| 66 | #define LA_UTCINFO_PROP_VALUE 1
|
---|
| 67 |
|
---|
| 68 |
|
---|
[96600] | 69 | /*********************************************************************************************************************************
|
---|
| 70 | * Structures and Typedefs *
|
---|
| 71 | *********************************************************************************************************************************/
|
---|
[57741] | 72 | typedef struct _VBOXLACONTEXT
|
---|
[40498] | 73 | {
|
---|
| 74 | const VBOXSERVICEENV *pEnv;
|
---|
| 75 |
|
---|
[40797] | 76 | bool fLogEnabled;
|
---|
[40866] | 77 | bool fDetachOnDisconnect;
|
---|
[40797] | 78 |
|
---|
[40498] | 79 | uint32_t u32GuestPropHandle; /* The client identifier of the guest property system. */
|
---|
| 80 |
|
---|
| 81 | RTLISTANCHOR listAttachActions;
|
---|
| 82 | RTLISTANCHOR listDetachActions;
|
---|
| 83 |
|
---|
| 84 | uint64_t u64LastQuery; /* The timestamp of the last query of the properties. */
|
---|
| 85 |
|
---|
| 86 | uint32_t u32Action; /* Which action to do: LA_DO_*. */
|
---|
| 87 | uint32_t u32PrevAction; /* Which action were done last time. */
|
---|
| 88 |
|
---|
| 89 | struct /* Information about the client, which properties are monitored. */
|
---|
| 90 | {
|
---|
| 91 | uint32_t u32ClientId; /* The RDP client identifier. 0 if none. */
|
---|
| 92 |
|
---|
| 93 | uint32_t u32LastAttach;
|
---|
| 94 | uint64_t u64LastAttachTimestamp;
|
---|
| 95 |
|
---|
| 96 | char *pszLastName;
|
---|
| 97 | uint64_t u64LastNameTimestamp;
|
---|
| 98 |
|
---|
[43584] | 99 | char *pszPropName; /* The actual Client/%ID%/Name property name with client id. */
|
---|
| 100 | char *pszPropIPAddr; /* The actual Client/%ID%/IPAddr property name with client id. */
|
---|
| 101 | char *pszPropLocation; /* The actual Client/%ID%/Location property name with client id. */
|
---|
| 102 | char *pszPropOtherInfo; /* The actual Client/%ID%/OtherInfo property name with client id. */
|
---|
| 103 |
|
---|
[40498] | 104 | char *pszPropAttach; /* The actual Client/%ID%/Attach property name with client id. */
|
---|
| 105 |
|
---|
| 106 | char *pszPropWaitPattern; /* Which properties are monitored. */
|
---|
| 107 | } activeClient;
|
---|
| 108 |
|
---|
| 109 | BOOL (WINAPI * pfnProcessIdToSessionId)(DWORD dwProcessId, DWORD *pSessionId);
|
---|
[57741] | 110 | } VBOXLACONTEXT, *PVBOXLACONTEXT;
|
---|
[40498] | 111 |
|
---|
[57741] | 112 | typedef struct _ACTIONENTRY
|
---|
[40498] | 113 | {
|
---|
| 114 | RTLISTNODE nodeActionEntry;
|
---|
| 115 | uint32_t u32Index;
|
---|
| 116 | WCHAR wszCommandLine[1];
|
---|
[57741] | 117 | } ACTIONENTRY, *PACTIONENTRY;
|
---|
[40498] | 118 |
|
---|
| 119 |
|
---|
[96600] | 120 | /*********************************************************************************************************************************
|
---|
| 121 | * Global Variables *
|
---|
| 122 | *********************************************************************************************************************************/
|
---|
[57741] | 123 | static VBOXLACONTEXT g_Ctx = { 0 };
|
---|
[40498] | 124 |
|
---|
[96600] | 125 | static const char * const g_pszPropActiveClient = "/VirtualBox/HostInfo/VRDP/ActiveClient";
|
---|
[40498] | 126 |
|
---|
[96600] | 127 | static const char * const g_pszPropAttachTemplate = "/VirtualBox/HostInfo/VRDP/Client/%u/Attach";
|
---|
[40498] | 128 |
|
---|
[96600] | 129 | static const char * const g_pszVolatileEnvironment = "Volatile Environment";
|
---|
[40498] | 130 |
|
---|
[96600] | 131 | static const WCHAR *const g_pwszClientName = L"CLIENTNAME";
|
---|
[40498] | 132 |
|
---|
[96600] | 133 | static const WCHAR * const g_pwszUTCINFOClientInfo[] =
|
---|
| 134 | {
|
---|
| 135 | L"UTCINFO_CLIENTNAME",
|
---|
| 136 | L"UTCINFO_CLIENTIPA",
|
---|
| 137 | L"UTCINFO_CLIENTLOCATION",
|
---|
| 138 | L"UTCINFO_CLIENTOTHERINFO"
|
---|
| 139 | };
|
---|
[43584] | 140 |
|
---|
[96600] | 141 | static const char * const g_pszPropInfoTemplates[] =
|
---|
| 142 | {
|
---|
| 143 | "/VirtualBox/HostInfo/VRDP/Client/%u/Name",
|
---|
| 144 | "/VirtualBox/HostInfo/VRDP/Client/%u/IPAddr",
|
---|
| 145 | "/VirtualBox/HostInfo/VRDP/Client/%u/Location",
|
---|
| 146 | "/VirtualBox/HostInfo/VRDP/Client/%u/OtherInfo"
|
---|
| 147 | };
|
---|
[43584] | 148 |
|
---|
[40664] | 149 | #ifdef RT_ARCH_AMD64
|
---|
[96600] | 150 | static const WCHAR *g_pwszRegKeyDisconnectActions = L"Software\\Wow6432Node\\Oracle\\Sun Ray\\ClientInfoAgent\\DisconnectActions";
|
---|
| 151 | static const WCHAR *g_pwszRegKeyReconnectActions = L"Software\\Wow6432Node\\Oracle\\Sun Ray\\ClientInfoAgent\\ReconnectActions";
|
---|
[40664] | 152 | #else
|
---|
[96600] | 153 | static const WCHAR *g_pwszRegKeyDisconnectActions = L"Software\\Oracle\\Sun Ray\\ClientInfoAgent\\DisconnectActions";
|
---|
| 154 | static const WCHAR *g_pwszRegKeyReconnectActions = L"Software\\Oracle\\Sun Ray\\ClientInfoAgent\\ReconnectActions";
|
---|
[40664] | 155 | #endif /* !RT_ARCH_AMD64 */
|
---|
[40498] | 156 |
|
---|
[96600] | 157 | static const char g_szCommandPrefix[] = "Command";
|
---|
[40498] | 158 |
|
---|
[96600] | 159 |
|
---|
[99828] | 160 | static BOOL laGetRegistryDWORD(const WCHAR *pwszRegKey, const WCHAR *pwszName, DWORD *pdwValue)
|
---|
[40797] | 161 | {
|
---|
| 162 | LONG lErr;
|
---|
| 163 |
|
---|
| 164 | HKEY hKey;
|
---|
| 165 | lErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
---|
| 166 | pwszRegKey,
|
---|
| 167 | 0,
|
---|
| 168 | KEY_QUERY_VALUE,
|
---|
| 169 | &hKey);
|
---|
| 170 |
|
---|
| 171 | if (lErr != ERROR_SUCCESS)
|
---|
| 172 | {
|
---|
[51469] | 173 | LogRel(("LA: RegOpenKeyExW: failed [%ls]\n",
|
---|
[40797] | 174 | pwszRegKey));
|
---|
| 175 | return FALSE;
|
---|
| 176 | }
|
---|
| 177 |
|
---|
| 178 | DWORD nRegData = sizeof(DWORD);
|
---|
| 179 | DWORD dwType = 0;
|
---|
| 180 | lErr = RegQueryValueExW(hKey,
|
---|
| 181 | pwszName,
|
---|
| 182 | NULL,
|
---|
| 183 | &dwType,
|
---|
| 184 | (BYTE *)pdwValue,
|
---|
| 185 | &nRegData);
|
---|
| 186 |
|
---|
| 187 | if (lErr != ERROR_SUCCESS)
|
---|
| 188 | {
|
---|
[51469] | 189 | LogRel(("LA: RegQueryValueExW: failed [%ls/%ls]\n",
|
---|
[40797] | 190 | pwszRegKey, pwszName));
|
---|
| 191 | RegCloseKey(hKey);
|
---|
| 192 | return FALSE;
|
---|
| 193 | }
|
---|
| 194 |
|
---|
| 195 | if (nRegData != sizeof(DWORD))
|
---|
| 196 | {
|
---|
[51469] | 197 | LogRel(("LA: buffer overflow reg %d, [%ls]\n",
|
---|
[40797] | 198 | nRegData, pwszRegKey));
|
---|
| 199 | RegCloseKey(hKey);
|
---|
| 200 | return FALSE;
|
---|
| 201 | }
|
---|
| 202 |
|
---|
| 203 | if (dwType != REG_DWORD)
|
---|
| 204 | {
|
---|
[51469] | 205 | LogRel(("LA: wrong type %d, [%ls/%ls]\n",
|
---|
[40797] | 206 | dwType, pwszRegKey, pwszName));
|
---|
| 207 | RegCloseKey(hKey);
|
---|
| 208 | return FALSE;
|
---|
| 209 | }
|
---|
| 210 |
|
---|
| 211 | RegCloseKey(hKey);
|
---|
| 212 |
|
---|
| 213 | if (lErr != ERROR_SUCCESS)
|
---|
| 214 | {
|
---|
| 215 | return FALSE;
|
---|
| 216 | }
|
---|
| 217 |
|
---|
| 218 | return TRUE;
|
---|
| 219 | }
|
---|
| 220 |
|
---|
[40498] | 221 | static void ActionExecutorDeleteActions(RTLISTANCHOR *listActions)
|
---|
| 222 | {
|
---|
[64766] | 223 | ACTIONENTRY *pIter;
|
---|
| 224 | ACTIONENTRY *pIterNext;
|
---|
[40498] | 225 | RTListForEachSafe(listActions, pIter, pIterNext, ACTIONENTRY, nodeActionEntry)
|
---|
| 226 | {
|
---|
| 227 | RTListNodeRemove(&pIter->nodeActionEntry);
|
---|
| 228 | RTMemFree(pIter);
|
---|
| 229 | }
|
---|
| 230 | }
|
---|
| 231 |
|
---|
| 232 | static BOOL ActionExecutorEnumerateRegistryKey(const WCHAR *pwszRegKey,
|
---|
| 233 | RTLISTANCHOR *listActions)
|
---|
| 234 | {
|
---|
| 235 | BOOL bRet = TRUE;
|
---|
| 236 | HKEY hKey;
|
---|
| 237 | DWORD dwErr;
|
---|
| 238 |
|
---|
| 239 | dwErr = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
|
---|
| 240 | pwszRegKey,
|
---|
| 241 | 0,
|
---|
| 242 | KEY_QUERY_VALUE,
|
---|
| 243 | &hKey);
|
---|
| 244 |
|
---|
| 245 | if (dwErr != ERROR_SUCCESS)
|
---|
| 246 | {
|
---|
[51469] | 247 | LogFlowFunc(("Can't open registry key [%ls], error %d\n",
|
---|
[40498] | 248 | pwszRegKey, dwErr));
|
---|
| 249 | return FALSE;
|
---|
| 250 | }
|
---|
| 251 |
|
---|
| 252 | DWORD dwIndex = 0;
|
---|
| 253 |
|
---|
| 254 | for (;;)
|
---|
| 255 | {
|
---|
| 256 | DWORD dwRet;
|
---|
| 257 |
|
---|
| 258 | WCHAR wszValueName[256];
|
---|
| 259 | DWORD cchValueName = RT_ELEMENTS(wszValueName);
|
---|
| 260 | DWORD type;
|
---|
| 261 | BYTE abData[1024];
|
---|
| 262 | DWORD cbData = sizeof(abData);
|
---|
| 263 |
|
---|
| 264 | dwRet = RegEnumValueW(hKey,
|
---|
| 265 | dwIndex++,
|
---|
| 266 | wszValueName,
|
---|
| 267 | &cchValueName,
|
---|
| 268 | NULL,
|
---|
| 269 | &type,
|
---|
| 270 | abData,
|
---|
| 271 | &cbData);
|
---|
| 272 |
|
---|
| 273 | if (dwRet == ERROR_NO_MORE_ITEMS)
|
---|
| 274 | {
|
---|
[51469] | 275 | LogFlowFunc(("Enumeration exhausted\n"));
|
---|
[40498] | 276 | bRet = TRUE;
|
---|
| 277 | break;
|
---|
| 278 | }
|
---|
| 279 | else if (dwRet != ERROR_SUCCESS)
|
---|
| 280 | {
|
---|
[51469] | 281 | LogFlowFunc(("Enumeration failed, error %d\n",
|
---|
[40498] | 282 | dwRet));
|
---|
| 283 | bRet = FALSE;
|
---|
| 284 | break;
|
---|
| 285 | }
|
---|
| 286 |
|
---|
| 287 | if ((type != REG_SZ) && (type != REG_EXPAND_SZ))
|
---|
| 288 | {
|
---|
[51469] | 289 | LogFlowFunc(("skipped type %d\n",
|
---|
[40498] | 290 | type));
|
---|
| 291 | continue;
|
---|
| 292 | }
|
---|
| 293 |
|
---|
| 294 | char szName[256];
|
---|
| 295 | char *pszName = &szName[0];
|
---|
| 296 | int rc = RTUtf16ToUtf8Ex(wszValueName,
|
---|
| 297 | RT_ELEMENTS(wszValueName),
|
---|
| 298 | &pszName, sizeof(szName), NULL);
|
---|
| 299 | if (RT_FAILURE(rc))
|
---|
| 300 | {
|
---|
[51469] | 301 | LogFlowFunc(("RTUtf16ToUtf8Ex for [%ls] rc %Rrc\n",
|
---|
[40498] | 302 | wszValueName, rc));
|
---|
| 303 | continue;
|
---|
| 304 | }
|
---|
| 305 |
|
---|
| 306 | /* Check if the name starts with "Command" */
|
---|
| 307 | if (RTStrNICmp(szName, g_szCommandPrefix, RT_ELEMENTS(g_szCommandPrefix) - 1) != 0)
|
---|
| 308 | {
|
---|
[51469] | 309 | LogFlowFunc(("skipped prefix %s\n",
|
---|
[40498] | 310 | szName));
|
---|
| 311 | continue;
|
---|
| 312 | }
|
---|
| 313 |
|
---|
| 314 | char *pszIndex = &szName[RT_ELEMENTS(g_szCommandPrefix) - 1];
|
---|
| 315 |
|
---|
| 316 | uint32_t nIndex = RTStrToUInt32(pszIndex);
|
---|
| 317 | if (nIndex == 0)
|
---|
| 318 | {
|
---|
[51469] | 319 | LogFlowFunc(("skipped index %s\n",
|
---|
[40498] | 320 | szName));
|
---|
| 321 | continue;
|
---|
| 322 | }
|
---|
| 323 |
|
---|
| 324 | /* Allocate with terminating nul after data. */
|
---|
| 325 | ACTIONENTRY *pEntry = (ACTIONENTRY *)RTMemAlloc(sizeof(ACTIONENTRY) + cbData);
|
---|
| 326 | if (!pEntry)
|
---|
| 327 | {
|
---|
[51469] | 328 | LogFlowFunc(("RTMemAlloc failed\n"));
|
---|
[40498] | 329 | bRet = FALSE;
|
---|
| 330 | break;
|
---|
| 331 | }
|
---|
| 332 |
|
---|
| 333 | RT_ZERO(pEntry->nodeActionEntry);
|
---|
| 334 | pEntry->u32Index = nIndex;
|
---|
| 335 | memcpy(pEntry->wszCommandLine, abData, cbData);
|
---|
| 336 | pEntry->wszCommandLine[cbData / sizeof(WCHAR)] = 0;
|
---|
| 337 |
|
---|
| 338 | /* Insert the new entry to the list. Sort by index. */
|
---|
| 339 | if (RTListIsEmpty(listActions))
|
---|
| 340 | {
|
---|
| 341 | RTListAppend(listActions, &pEntry->nodeActionEntry);
|
---|
| 342 | }
|
---|
| 343 | else
|
---|
| 344 | {
|
---|
| 345 | bool fAdded = false;
|
---|
[64766] | 346 | ACTIONENTRY *pIter;
|
---|
[40498] | 347 | RTListForEach(listActions, pIter, ACTIONENTRY, nodeActionEntry)
|
---|
| 348 | {
|
---|
| 349 | if (pIter->u32Index > nIndex)
|
---|
| 350 | {
|
---|
| 351 | RTListNodeInsertBefore(&pIter->nodeActionEntry, &pEntry->nodeActionEntry);
|
---|
| 352 | fAdded = true;
|
---|
| 353 | break;
|
---|
| 354 | }
|
---|
| 355 | }
|
---|
| 356 | if (!fAdded)
|
---|
| 357 | {
|
---|
| 358 | RTListAppend(listActions, &pEntry->nodeActionEntry);
|
---|
| 359 | }
|
---|
| 360 | }
|
---|
| 361 |
|
---|
[51469] | 362 | LogFlowFunc(("added %d %ls\n",
|
---|
[40498] | 363 | pEntry->u32Index, pEntry->wszCommandLine));
|
---|
| 364 | }
|
---|
| 365 |
|
---|
| 366 | RegCloseKey(hKey);
|
---|
| 367 |
|
---|
| 368 | #ifdef LOG_ENABLED
|
---|
[64766] | 369 | ACTIONENTRY *pIter;
|
---|
[40498] | 370 | RTListForEach(listActions, pIter, ACTIONENTRY, nodeActionEntry)
|
---|
| 371 | {
|
---|
[51469] | 372 | LogFlowFunc(("[%u]: [%ls]\n",
|
---|
[40498] | 373 | pIter->u32Index, pIter->wszCommandLine));
|
---|
| 374 | }
|
---|
| 375 | #endif
|
---|
| 376 |
|
---|
| 377 | if (!bRet)
|
---|
| 378 | {
|
---|
| 379 | ActionExecutorDeleteActions(listActions);
|
---|
| 380 | }
|
---|
| 381 |
|
---|
[64766] | 382 | LogFlowFunc(("action enum %d\n", bRet));
|
---|
[40797] | 383 |
|
---|
[40498] | 384 | return bRet;
|
---|
| 385 | }
|
---|
| 386 |
|
---|
| 387 | static void ActionExecutorExecuteActions(RTLISTANCHOR *listActions)
|
---|
| 388 | {
|
---|
[51469] | 389 | LogFlowFunc(("ExecuteActions\n"));
|
---|
[40498] | 390 |
|
---|
[64766] | 391 | ACTIONENTRY *pIter;
|
---|
[40498] | 392 | RTListForEach(listActions, pIter, ACTIONENTRY, nodeActionEntry)
|
---|
| 393 | {
|
---|
[51469] | 394 | LogFlowFunc(("[%u]: [%ls]\n",
|
---|
[40498] | 395 | pIter->u32Index, pIter->wszCommandLine));
|
---|
| 396 |
|
---|
| 397 | STARTUPINFOW si;
|
---|
| 398 | PROCESS_INFORMATION pi;
|
---|
| 399 |
|
---|
| 400 | GetStartupInfoW(&si);
|
---|
| 401 |
|
---|
| 402 | if (!CreateProcessW(NULL, // lpApplicationName
|
---|
| 403 | pIter->wszCommandLine, // lpCommandLine
|
---|
| 404 | NULL, // lpProcessAttributes
|
---|
| 405 | NULL, // lpThreadAttributes
|
---|
| 406 | FALSE, // bInheritHandles
|
---|
| 407 | 0, // dwCreationFlags
|
---|
| 408 | NULL, // lpEnvironment
|
---|
| 409 | NULL, // lpCurrentDirectory
|
---|
| 410 | &si, // lpStartupInfo
|
---|
| 411 | &pi)) // lpProcessInformation
|
---|
| 412 | {
|
---|
[51469] | 413 | LogFlowFunc(("Executing [%ls] failed, error %d\n",
|
---|
[40498] | 414 | pIter->wszCommandLine, GetLastError()));
|
---|
| 415 | }
|
---|
| 416 | else
|
---|
| 417 | {
|
---|
[51469] | 418 | LogFlowFunc(("Executing [%ls] succeeded\n",
|
---|
[40498] | 419 | pIter->wszCommandLine));
|
---|
| 420 |
|
---|
| 421 | /* Don't care about waiting on the new process, so close these. */
|
---|
| 422 | CloseHandle(pi.hProcess);
|
---|
| 423 | CloseHandle(pi.hThread);
|
---|
| 424 | }
|
---|
| 425 | }
|
---|
| 426 |
|
---|
[51469] | 427 | LogFlowFunc(("ExecuteActions leave\n"));
|
---|
[40498] | 428 | }
|
---|
[43584] | 429 |
|
---|
[57741] | 430 | static BOOL GetVolatileEnvironmentKey(PVBOXLACONTEXT pCtx, WCHAR *pwszRegKey, DWORD cbRegKey)
|
---|
[40498] | 431 | {
|
---|
| 432 | BOOL fFound = FALSE;
|
---|
| 433 |
|
---|
| 434 | DWORD nSessionID;
|
---|
| 435 | LONG lErr;
|
---|
| 436 | HKEY hKey;
|
---|
| 437 | char szRegKey[REG_KEY_LEN];
|
---|
| 438 |
|
---|
| 439 | /* Attempt to open HKCU\Volatile Environment\<session ID> first. */
|
---|
[57741] | 440 | if ( pCtx->pfnProcessIdToSessionId
|
---|
| 441 | && pCtx->pfnProcessIdToSessionId(GetCurrentProcessId(), &nSessionID))
|
---|
[40498] | 442 | {
|
---|
| 443 | RTStrPrintf(szRegKey, sizeof(szRegKey),
|
---|
| 444 | "%s\\%d",
|
---|
| 445 | g_pszVolatileEnvironment, nSessionID);
|
---|
| 446 |
|
---|
| 447 | lErr = RegOpenKeyExA(HKEY_CURRENT_USER,
|
---|
| 448 | szRegKey,
|
---|
| 449 | 0,
|
---|
| 450 | KEY_SET_VALUE,
|
---|
| 451 | &hKey);
|
---|
| 452 |
|
---|
| 453 | if (lErr == ERROR_SUCCESS)
|
---|
| 454 | {
|
---|
| 455 | RegCloseKey(hKey);
|
---|
| 456 | fFound = TRUE;
|
---|
| 457 | }
|
---|
| 458 | }
|
---|
| 459 |
|
---|
| 460 | if (!fFound)
|
---|
| 461 | {
|
---|
| 462 | /* Fall back to HKCU\Volatile Environment. */
|
---|
| 463 | RTStrPrintf(szRegKey, sizeof(szRegKey),
|
---|
| 464 | "%s",
|
---|
| 465 | g_pszVolatileEnvironment);
|
---|
| 466 |
|
---|
| 467 | lErr = RegOpenKeyExA(HKEY_CURRENT_USER,
|
---|
| 468 | szRegKey,
|
---|
| 469 | 0,
|
---|
| 470 | KEY_SET_VALUE,
|
---|
| 471 | &hKey);
|
---|
| 472 |
|
---|
| 473 | if (lErr == ERROR_SUCCESS)
|
---|
| 474 | {
|
---|
| 475 | RegCloseKey(hKey);
|
---|
| 476 | fFound = TRUE;
|
---|
| 477 | }
|
---|
| 478 | }
|
---|
| 479 |
|
---|
| 480 | if (fFound)
|
---|
| 481 | {
|
---|
[51469] | 482 | LogFlowFunc(("GetVolatileEnvironmentKey: [%s]\n", szRegKey));
|
---|
[40498] | 483 |
|
---|
| 484 | /* Convert szRegKey to Utf16 string. */
|
---|
| 485 | PRTUTF16 putf16Unicode = pwszRegKey;
|
---|
| 486 | size_t cchUnicode = cbRegKey / sizeof(WCHAR);
|
---|
| 487 |
|
---|
| 488 | int rc = RTStrToUtf16Ex(szRegKey, RTSTR_MAX,
|
---|
| 489 | &putf16Unicode, cchUnicode, NULL);
|
---|
| 490 | if (RT_FAILURE(rc))
|
---|
| 491 | {
|
---|
[51469] | 492 | LogFlowFunc(("RTStrToUtf16Ex failed %Rrc\n", rc));
|
---|
[40498] | 493 | fFound = FALSE;
|
---|
| 494 | }
|
---|
| 495 | else
|
---|
| 496 | {
|
---|
[51469] | 497 | LogFlowFunc(("unicode [%ls]\n", putf16Unicode));
|
---|
[40498] | 498 | }
|
---|
| 499 | }
|
---|
| 500 | else
|
---|
| 501 | {
|
---|
[51469] | 502 | LogFlowFunc(("GetVolatileEnvironmentKey: not found\n"));
|
---|
[40498] | 503 | }
|
---|
| 504 |
|
---|
| 505 | return fFound;
|
---|
| 506 | }
|
---|
| 507 |
|
---|
[57741] | 508 | static BOOL laGetUtcInfoClientName(PVBOXLACONTEXT pCtx, WCHAR *pwszClientName, DWORD cbClientName)
|
---|
[40498] | 509 | {
|
---|
| 510 | LONG lErr;
|
---|
| 511 |
|
---|
| 512 | WCHAR wszRegKey[REG_KEY_LEN];
|
---|
[57741] | 513 | if (!GetVolatileEnvironmentKey(pCtx, wszRegKey, sizeof(wszRegKey)))
|
---|
[40498] | 514 | {
|
---|
| 515 | return FALSE;
|
---|
| 516 | }
|
---|
| 517 |
|
---|
| 518 | HKEY hKey;
|
---|
| 519 | lErr = RegOpenKeyExW(HKEY_CURRENT_USER,
|
---|
| 520 | wszRegKey,
|
---|
| 521 | 0,
|
---|
| 522 | KEY_QUERY_VALUE,
|
---|
| 523 | &hKey);
|
---|
| 524 |
|
---|
| 525 | if (lErr != ERROR_SUCCESS)
|
---|
| 526 | {
|
---|
[51469] | 527 | LogFlowFunc(("RegOpenKeyExW: failed [%ls]\n",
|
---|
[40498] | 528 | wszRegKey));
|
---|
| 529 | return FALSE;
|
---|
| 530 | }
|
---|
| 531 |
|
---|
| 532 | DWORD nRegData;
|
---|
| 533 | DWORD dwType;
|
---|
| 534 | lErr = RegQueryValueExW(hKey,
|
---|
[43584] | 535 | g_pwszUTCINFOClientInfo[LA_UTCINFO_CLIENT_NAME],
|
---|
[40498] | 536 | NULL,
|
---|
| 537 | &dwType,
|
---|
| 538 | NULL,
|
---|
| 539 | &nRegData);
|
---|
| 540 |
|
---|
| 541 | if (lErr != ERROR_SUCCESS)
|
---|
| 542 | {
|
---|
[51469] | 543 | LogFlowFunc(("RegQueryValueExW: failed [%ls]\n",
|
---|
[40498] | 544 | wszRegKey));
|
---|
| 545 | RegCloseKey(hKey);
|
---|
| 546 | return FALSE;
|
---|
| 547 | }
|
---|
| 548 |
|
---|
| 549 | if (nRegData >= cbClientName)
|
---|
| 550 | {
|
---|
[51469] | 551 | LogFlowFunc(("buffer overflow reg %d, buffer %d, [%ls]\n",
|
---|
[40498] | 552 | nRegData, cbClientName, wszRegKey));
|
---|
| 553 | RegCloseKey(hKey);
|
---|
| 554 | return FALSE;
|
---|
| 555 | }
|
---|
| 556 |
|
---|
| 557 | if (dwType != REG_SZ)
|
---|
| 558 | {
|
---|
[51469] | 559 | LogFlowFunc(("wrong type %d, [%ls]\n",
|
---|
[40498] | 560 | dwType, wszRegKey));
|
---|
| 561 | RegCloseKey(hKey);
|
---|
| 562 | return FALSE;
|
---|
| 563 | }
|
---|
| 564 |
|
---|
| 565 | ZeroMemory(pwszClientName, cbClientName);
|
---|
| 566 |
|
---|
| 567 | lErr = RegQueryValueExW(hKey,
|
---|
[43584] | 568 | g_pwszUTCINFOClientInfo[LA_UTCINFO_CLIENT_NAME],
|
---|
[40498] | 569 | NULL,
|
---|
| 570 | NULL,
|
---|
| 571 | (BYTE *)pwszClientName,
|
---|
| 572 | &nRegData);
|
---|
| 573 |
|
---|
| 574 | RegCloseKey(hKey);
|
---|
| 575 |
|
---|
| 576 | if (lErr != ERROR_SUCCESS)
|
---|
| 577 | {
|
---|
| 578 | return FALSE;
|
---|
| 579 | }
|
---|
| 580 |
|
---|
| 581 | return TRUE;
|
---|
| 582 | }
|
---|
| 583 |
|
---|
[57741] | 584 | static BOOL laSetClientName(PVBOXLACONTEXT pCtx, const WCHAR *pwszClientName)
|
---|
[40498] | 585 | {
|
---|
| 586 | LONG lErr;
|
---|
| 587 |
|
---|
| 588 | WCHAR wszRegKey[REG_KEY_LEN];
|
---|
[57741] | 589 | if (!GetVolatileEnvironmentKey(pCtx, wszRegKey, sizeof(wszRegKey)))
|
---|
[40498] | 590 | {
|
---|
| 591 | return FALSE;
|
---|
| 592 | }
|
---|
| 593 |
|
---|
| 594 | HKEY hKey;
|
---|
| 595 | lErr = RegOpenKeyExW(HKEY_CURRENT_USER,
|
---|
| 596 | wszRegKey,
|
---|
| 597 | 0,
|
---|
| 598 | KEY_SET_VALUE,
|
---|
| 599 | &hKey);
|
---|
| 600 |
|
---|
| 601 | if (lErr != ERROR_SUCCESS)
|
---|
| 602 | {
|
---|
| 603 | return FALSE;
|
---|
| 604 | }
|
---|
| 605 |
|
---|
| 606 | DWORD nClientName = (lstrlenW(pwszClientName) + 1) * sizeof(WCHAR);
|
---|
| 607 | lErr = RegSetValueExW(hKey,
|
---|
| 608 | g_pwszClientName,
|
---|
| 609 | 0,
|
---|
| 610 | REG_SZ,
|
---|
| 611 | (BYTE*)pwszClientName,
|
---|
| 612 | nClientName);
|
---|
| 613 |
|
---|
| 614 | RegCloseKey(hKey);
|
---|
| 615 |
|
---|
| 616 | if (lErr != ERROR_SUCCESS)
|
---|
| 617 | {
|
---|
| 618 | return FALSE;
|
---|
| 619 | }
|
---|
| 620 |
|
---|
| 621 | return TRUE;
|
---|
| 622 | }
|
---|
| 623 |
|
---|
| 624 | static void laBroadcastSettingChange(void)
|
---|
| 625 | {
|
---|
| 626 | DWORD_PTR dwResult;
|
---|
| 627 |
|
---|
| 628 | if (SendMessageTimeoutA(HWND_BROADCAST,
|
---|
| 629 | WM_SETTINGCHANGE,
|
---|
| 630 | NULL,
|
---|
| 631 | (LPARAM)"Environment",
|
---|
| 632 | SMTO_ABORTIFHUNG,
|
---|
| 633 | 5000,
|
---|
| 634 | &dwResult) == 0)
|
---|
| 635 | {
|
---|
[57741] | 636 | LogFlowFunc(("SendMessageTimeout failed, error %ld\n", GetLastError()));
|
---|
[40498] | 637 | }
|
---|
| 638 | }
|
---|
| 639 |
|
---|
[57741] | 640 | static void laUpdateClientName(PVBOXLACONTEXT pCtx)
|
---|
[40498] | 641 | {
|
---|
| 642 | WCHAR wszUtcInfoClientName[MAX_CLIENT_NAME_CHARS];
|
---|
| 643 |
|
---|
[57741] | 644 | if (laGetUtcInfoClientName(pCtx, wszUtcInfoClientName, sizeof(wszUtcInfoClientName)))
|
---|
[40498] | 645 | {
|
---|
[57741] | 646 | if (laSetClientName(pCtx, wszUtcInfoClientName))
|
---|
[40498] | 647 | laBroadcastSettingChange();
|
---|
| 648 | }
|
---|
| 649 | }
|
---|
| 650 |
|
---|
[57741] | 651 | static void laOnClientLocationInfo(PVBOXLACONTEXT pCtx, char *pszClientInfo[][2])
|
---|
[40498] | 652 | {
|
---|
| 653 | /*
|
---|
[43584] | 654 | * Write the client location info to:
|
---|
| 655 | * HKCU\Volatile Environment\<CLIENT_LOCATION_INFO> or
|
---|
| 656 | * HKCU\Volatile Environment\<SessionID>\<CLIENT_LOCATION_INFO>
|
---|
[40498] | 657 | * depending on whether this is a Terminal Services or desktop session
|
---|
| 658 | * respectively.
|
---|
[43584] | 659 | * The client location info are: Name, IPAddr, Location, OtherInfo
|
---|
[40498] | 660 | */
|
---|
[43584] | 661 | unsigned int idx;
|
---|
[40498] | 662 | WCHAR wszRegKey[REG_KEY_LEN];
|
---|
[57741] | 663 | if (!GetVolatileEnvironmentKey(pCtx, wszRegKey, sizeof(wszRegKey)))
|
---|
[40498] | 664 | {
|
---|
[51469] | 665 | LogFlowFunc(("Failed to get 'Volatile Environment' registry key\n"));
|
---|
[40498] | 666 | return;
|
---|
| 667 | }
|
---|
| 668 |
|
---|
| 669 | /* Now write the client name under the appropriate key. */
|
---|
| 670 | LONG lRet;
|
---|
| 671 | HKEY hKey;
|
---|
| 672 |
|
---|
| 673 | lRet = RegOpenKeyExW(HKEY_CURRENT_USER,
|
---|
| 674 | wszRegKey,
|
---|
| 675 | 0,
|
---|
| 676 | KEY_SET_VALUE,
|
---|
| 677 | &hKey);
|
---|
| 678 |
|
---|
| 679 | if (lRet != ERROR_SUCCESS)
|
---|
| 680 | {
|
---|
[57741] | 681 | LogFlowFunc(("Failed to open key [%ls], error %lu\n", wszRegKey, lRet));
|
---|
[40498] | 682 | return;
|
---|
| 683 | }
|
---|
| 684 |
|
---|
[43584] | 685 | PRTUTF16 putf16UnicodeClientInfo[LA_UTCINFO_CLIENT_INFO_LAST + 1] = {NULL};
|
---|
| 686 | for (idx = 0; idx <= LA_UTCINFO_CLIENT_INFO_LAST; idx++)
|
---|
| 687 | {
|
---|
| 688 | if (pszClientInfo[idx][LA_UTCINFO_PROP_VALUE] == NULL)
|
---|
| 689 | break;
|
---|
[40498] | 690 |
|
---|
[43584] | 691 | /* pszClientInfo is UTF8, make an Unicode copy for registry. */
|
---|
| 692 | size_t cchUnicodeClientInfo = 0;
|
---|
| 693 |
|
---|
| 694 | int rc = RTStrToUtf16Ex(pszClientInfo[idx][LA_UTCINFO_PROP_VALUE], MAX_CLIENT_NAME_CHARS,
|
---|
| 695 | &putf16UnicodeClientInfo[idx], 0, &cchUnicodeClientInfo);
|
---|
| 696 |
|
---|
| 697 | if (RT_FAILURE(rc))
|
---|
| 698 | {
|
---|
[51469] | 699 | LogFlowFunc(("RTStrToUniEx failed %Rrc\n", rc));
|
---|
[43584] | 700 | break;
|
---|
| 701 | }
|
---|
| 702 |
|
---|
| 703 | DWORD nDataLength = (DWORD)((cchUnicodeClientInfo + 1) * sizeof(WCHAR));
|
---|
| 704 | lRet = RegSetValueExW(hKey,
|
---|
| 705 | g_pwszUTCINFOClientInfo[idx],
|
---|
| 706 | 0,
|
---|
| 707 | REG_SZ,
|
---|
| 708 | (BYTE *)putf16UnicodeClientInfo[idx],
|
---|
| 709 | nDataLength);
|
---|
| 710 |
|
---|
| 711 | if (lRet != ERROR_SUCCESS)
|
---|
| 712 | {
|
---|
[51469] | 713 | LogFlowFunc(("RegSetValueExW failed error %lu for %s \n", lRet, g_pwszUTCINFOClientInfo[idx]));
|
---|
[43584] | 714 | }
|
---|
[40498] | 715 | }
|
---|
| 716 |
|
---|
| 717 | RegCloseKey(hKey);
|
---|
| 718 |
|
---|
| 719 | laBroadcastSettingChange();
|
---|
| 720 |
|
---|
[43584] | 721 | /* Also, write these info (Name, IPAddr, Location and Other Info) to the environment of this process, as it
|
---|
[40498] | 722 | * doesn't listen for WM_SETTINGCHANGE messages.
|
---|
| 723 | */
|
---|
| 724 |
|
---|
[43584] | 725 | for (idx = 0; idx <= LA_UTCINFO_CLIENT_INFO_LAST; idx++)
|
---|
| 726 | {
|
---|
| 727 | if (putf16UnicodeClientInfo[idx] == NULL)
|
---|
| 728 | break;
|
---|
| 729 |
|
---|
| 730 | SetEnvironmentVariableW(g_pwszUTCINFOClientInfo[idx], putf16UnicodeClientInfo[idx]);
|
---|
| 731 |
|
---|
| 732 | RTUtf16Free(putf16UnicodeClientInfo[idx]);
|
---|
| 733 | }
|
---|
[40498] | 734 | }
|
---|
| 735 |
|
---|
[57741] | 736 | static void laDoAttach(PVBOXLACONTEXT pCtx)
|
---|
[40498] | 737 | {
|
---|
[51469] | 738 | LogFlowFunc(("laDoAttach\n"));
|
---|
[40498] | 739 |
|
---|
| 740 | /* Hardcoded action. */
|
---|
| 741 | laUpdateClientName(pCtx);
|
---|
| 742 |
|
---|
| 743 | /* Process configured actions. */
|
---|
| 744 | ActionExecutorExecuteActions(&pCtx->listAttachActions);
|
---|
| 745 | }
|
---|
| 746 |
|
---|
[57741] | 747 | static void laDoDetach(PVBOXLACONTEXT pCtx)
|
---|
[40498] | 748 | {
|
---|
[51469] | 749 | LogFlowFunc(("laDoDetach\n"));
|
---|
[40498] | 750 |
|
---|
| 751 | /* Process configured actions. */
|
---|
| 752 | ActionExecutorExecuteActions(&pCtx->listDetachActions);
|
---|
| 753 | }
|
---|
| 754 |
|
---|
| 755 | static int laGetProperty(uint32_t u32GuestPropHandle, const char *pszName, uint64_t *pu64Timestamp, char **ppszValue)
|
---|
| 756 | {
|
---|
| 757 | int rc = VINF_SUCCESS;
|
---|
| 758 |
|
---|
| 759 | /* The buffer for storing the data and its initial size. We leave a bit
|
---|
| 760 | * of space here in case the maximum values are raised.
|
---|
| 761 | */
|
---|
| 762 | uint32_t cbBuf = 1024;
|
---|
| 763 | void *pvBuf = NULL;
|
---|
| 764 |
|
---|
| 765 | /* Because there is a race condition between our reading the size of a
|
---|
| 766 | * property and the guest updating it, we loop a few times here and
|
---|
| 767 | * hope. Actually this should never go wrong, as we are generous
|
---|
| 768 | * enough with buffer space.
|
---|
| 769 | */
|
---|
| 770 | unsigned i;
|
---|
| 771 | for (i = 0; i < 3; ++i)
|
---|
| 772 | {
|
---|
| 773 | void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
|
---|
| 774 | if (pvTmpBuf == NULL)
|
---|
| 775 | {
|
---|
| 776 | rc = VERR_NO_MEMORY;
|
---|
| 777 | break;
|
---|
| 778 | }
|
---|
| 779 |
|
---|
| 780 | pvBuf = pvTmpBuf;
|
---|
| 781 |
|
---|
| 782 | rc = VbglR3GuestPropRead(u32GuestPropHandle, pszName, pvBuf, cbBuf,
|
---|
| 783 | NULL, pu64Timestamp, NULL,
|
---|
| 784 | &cbBuf);
|
---|
| 785 | if (rc != VERR_BUFFER_OVERFLOW)
|
---|
| 786 | {
|
---|
| 787 | break;
|
---|
| 788 | }
|
---|
| 789 |
|
---|
| 790 | cbBuf += 1024;
|
---|
| 791 | }
|
---|
| 792 |
|
---|
| 793 | if (RT_SUCCESS(rc))
|
---|
| 794 | {
|
---|
[51469] | 795 | LogFlowFunc(("laGetProperty: [%s]\n"
|
---|
[40498] | 796 | " value: [%s]\n"
|
---|
| 797 | " timestamp: %lld ns\n",
|
---|
| 798 | pszName, (char *)pvBuf, *pu64Timestamp));
|
---|
| 799 |
|
---|
| 800 | *ppszValue = (char *)pvBuf;
|
---|
| 801 | }
|
---|
| 802 | else if (rc == VERR_NOT_FOUND)
|
---|
| 803 | {
|
---|
[51469] | 804 | LogFlowFunc(("laGetProperty: not found [%s]\n", pszName));
|
---|
[43224] | 805 | RTMemFree(pvBuf);
|
---|
[40498] | 806 | }
|
---|
| 807 | else
|
---|
| 808 | {
|
---|
[51469] | 809 | LogFlowFunc(("Failed to retrieve the property value, error %Rrc\n", rc));
|
---|
[43224] | 810 | RTMemFree(pvBuf);
|
---|
[40498] | 811 | }
|
---|
| 812 |
|
---|
| 813 | return rc;
|
---|
| 814 | }
|
---|
| 815 |
|
---|
| 816 | static int laWaitProperties(uint32_t u32GuestPropHandle,
|
---|
| 817 | const char *pszPatterns,
|
---|
| 818 | uint64_t u64LastTimestamp,
|
---|
| 819 | uint64_t *pu64Timestamp,
|
---|
| 820 | uint32_t u32Timeout)
|
---|
| 821 | {
|
---|
| 822 | int rc = VINF_SUCCESS;
|
---|
| 823 |
|
---|
| 824 | /* The buffer for storing the data and its initial size. We leave a bit
|
---|
| 825 | * of space here in case the maximum values are raised.
|
---|
| 826 | */
|
---|
| 827 | void *pvBuf = NULL;
|
---|
| 828 | uint32_t cbBuf = 4096;
|
---|
| 829 |
|
---|
| 830 | /* Because there is a race condition between our reading the size of a
|
---|
| 831 | * property and the guest updating it, we loop a few times here and
|
---|
| 832 | * hope. Actually this should never go wrong, as we are generous
|
---|
| 833 | * enough with buffer space.
|
---|
| 834 | */
|
---|
| 835 | unsigned i;
|
---|
| 836 | for (i = 0; i < 3; ++i)
|
---|
| 837 | {
|
---|
| 838 | void *pvTmpBuf = RTMemRealloc(pvBuf, cbBuf);
|
---|
| 839 | if (NULL == pvTmpBuf)
|
---|
| 840 | {
|
---|
| 841 | rc = VERR_NO_MEMORY;
|
---|
| 842 | break;
|
---|
| 843 | }
|
---|
| 844 |
|
---|
| 845 | pvBuf = pvTmpBuf;
|
---|
| 846 |
|
---|
| 847 | rc = VbglR3GuestPropWait(u32GuestPropHandle, pszPatterns, pvBuf, cbBuf,
|
---|
| 848 | u64LastTimestamp, u32Timeout,
|
---|
| 849 | NULL /* ppszName */,
|
---|
| 850 | NULL /* ppszValue */,
|
---|
| 851 | pu64Timestamp,
|
---|
| 852 | NULL /* ppszFlags */,
|
---|
[94184] | 853 | &cbBuf,
|
---|
| 854 | NULL /* pfWasDeleted */);
|
---|
[40498] | 855 |
|
---|
| 856 | if (rc != VERR_BUFFER_OVERFLOW)
|
---|
| 857 | break;
|
---|
| 858 |
|
---|
| 859 | cbBuf += 1024;
|
---|
| 860 | }
|
---|
| 861 |
|
---|
| 862 | RTMemFree(pvBuf);
|
---|
| 863 |
|
---|
| 864 | return rc;
|
---|
| 865 | }
|
---|
| 866 |
|
---|
| 867 | static int laGetUint32(uint32_t u32GuestPropHandle, const char *pszName, uint64_t *pu64Timestamp, uint32_t *pu32Value)
|
---|
| 868 | {
|
---|
| 869 | uint64_t u64Timestamp = 0;
|
---|
| 870 | char *pszValue = NULL;
|
---|
| 871 |
|
---|
| 872 | int rc = laGetProperty(u32GuestPropHandle,
|
---|
| 873 | pszName,
|
---|
| 874 | &u64Timestamp,
|
---|
| 875 | &pszValue);
|
---|
| 876 | if (RT_SUCCESS(rc))
|
---|
| 877 | {
|
---|
| 878 | if (pszValue && *pszValue)
|
---|
| 879 | {
|
---|
| 880 | uint32_t u32 = 0;
|
---|
| 881 | rc = RTStrToUInt32Full(pszValue, 10, &u32);
|
---|
| 882 |
|
---|
| 883 | if (RT_SUCCESS(rc))
|
---|
| 884 | {
|
---|
| 885 | *pu64Timestamp = u64Timestamp;
|
---|
| 886 | *pu32Value = u32;
|
---|
| 887 | }
|
---|
| 888 | }
|
---|
| 889 | else
|
---|
| 890 | {
|
---|
| 891 | rc = VERR_NOT_SUPPORTED;
|
---|
| 892 | }
|
---|
| 893 | }
|
---|
| 894 |
|
---|
| 895 | if (pszValue)
|
---|
| 896 | RTMemFree(pszValue);
|
---|
| 897 |
|
---|
[57741] | 898 | LogFlowFunc(("laGetUint32: rc = %Rrc, [%s]\n", rc, pszName));
|
---|
[40498] | 899 | return rc;
|
---|
| 900 | }
|
---|
| 901 |
|
---|
| 902 | static int laGetString(uint32_t u32GuestPropHandle, const char *pszName, uint64_t *pu64Timestamp, char **ppszValue)
|
---|
| 903 | {
|
---|
| 904 | int rc = laGetProperty(u32GuestPropHandle,
|
---|
| 905 | pszName,
|
---|
| 906 | pu64Timestamp,
|
---|
| 907 | ppszValue);
|
---|
| 908 |
|
---|
[57741] | 909 | LogFlowFunc(("laGetString: rc = %Rrc, [%s]\n", rc, pszName));
|
---|
[40498] | 910 | return rc;
|
---|
| 911 | }
|
---|
| 912 |
|
---|
[57741] | 913 | static int laGetActiveClient(PVBOXLACONTEXT pCtx, uint64_t *pu64Timestamp, uint32_t *pu32Value)
|
---|
[40498] | 914 | {
|
---|
| 915 | int rc = laGetUint32(pCtx->u32GuestPropHandle,
|
---|
| 916 | g_pszPropActiveClient,
|
---|
| 917 | pu64Timestamp,
|
---|
| 918 | pu32Value);
|
---|
| 919 |
|
---|
[57741] | 920 | LogFlowFunc(("laGetActiveClient: rc %Rrc, %RU32, %RU64\n", rc, *pu32Value, *pu64Timestamp));
|
---|
[40498] | 921 | return rc;
|
---|
| 922 | }
|
---|
| 923 |
|
---|
[57741] | 924 | static int laUpdateCurrentState(PVBOXLACONTEXT pCtx, uint32_t u32ActiveClientId, uint64_t u64ActiveClientTS)
|
---|
[40498] | 925 | {
|
---|
| 926 | /* Prepare the current state for the active client.
|
---|
| 927 | * If u32ActiveClientId is 0, then there is no connected clients.
|
---|
| 928 | */
|
---|
[57741] | 929 | LogFlowFunc(("laUpdateCurrentState: %RU32 %RU64\n", u32ActiveClientId, u64ActiveClientTS));
|
---|
[40498] | 930 |
|
---|
| 931 | int rc = VINF_SUCCESS;
|
---|
| 932 |
|
---|
| 933 | int l;
|
---|
| 934 |
|
---|
[63104] | 935 | char **pClientInfoMap[LA_UTCINFO_CLIENT_INFO_LAST + 1] =
|
---|
| 936 | {
|
---|
| 937 | &pCtx->activeClient.pszPropName,
|
---|
| 938 | &pCtx->activeClient.pszPropIPAddr,
|
---|
| 939 | &pCtx->activeClient.pszPropLocation,
|
---|
| 940 | &pCtx->activeClient.pszPropOtherInfo,
|
---|
| 941 | };
|
---|
[43584] | 942 |
|
---|
[63104] | 943 | pCtx->activeClient.u32LastAttach = UINT32_MAX;
|
---|
[40498] | 944 | pCtx->activeClient.u64LastAttachTimestamp = u64ActiveClientTS;
|
---|
| 945 |
|
---|
| 946 | if (pCtx->activeClient.pszLastName)
|
---|
| 947 | {
|
---|
| 948 | RTMemFree(pCtx->activeClient.pszLastName);
|
---|
| 949 | }
|
---|
| 950 | pCtx->activeClient.pszLastName = NULL;
|
---|
| 951 | pCtx->activeClient.u64LastNameTimestamp = u64ActiveClientTS;
|
---|
| 952 |
|
---|
[43584] | 953 | unsigned int idx;
|
---|
| 954 |
|
---|
| 955 | for (idx = 0; idx <= LA_UTCINFO_CLIENT_INFO_LAST; idx++)
|
---|
[40498] | 956 | {
|
---|
[43584] | 957 | if (*pClientInfoMap[idx])
|
---|
[40498] | 958 | {
|
---|
[43584] | 959 | RTMemFree(*pClientInfoMap[idx]);
|
---|
| 960 | *pClientInfoMap[idx] = NULL;
|
---|
[40498] | 961 | }
|
---|
[43584] | 962 |
|
---|
| 963 | if (u32ActiveClientId != 0)
|
---|
| 964 | {
|
---|
| 965 | l = RTStrAPrintf(pClientInfoMap[idx],
|
---|
| 966 | g_pszPropInfoTemplates[idx],
|
---|
| 967 | u32ActiveClientId);
|
---|
| 968 |
|
---|
| 969 | if (l == -1)
|
---|
| 970 | {
|
---|
| 971 | *pClientInfoMap[idx] = NULL;
|
---|
| 972 | rc = VERR_NO_MEMORY;
|
---|
| 973 | break;
|
---|
| 974 | }
|
---|
| 975 | }
|
---|
[40498] | 976 | }
|
---|
| 977 |
|
---|
| 978 | if (RT_SUCCESS(rc))
|
---|
| 979 | {
|
---|
| 980 | if (pCtx->activeClient.pszPropAttach)
|
---|
| 981 | {
|
---|
| 982 | RTMemFree(pCtx->activeClient.pszPropAttach);
|
---|
| 983 | pCtx->activeClient.pszPropAttach = NULL;
|
---|
| 984 | }
|
---|
| 985 | if (u32ActiveClientId != 0)
|
---|
| 986 | {
|
---|
| 987 | l = RTStrAPrintf(&pCtx->activeClient.pszPropAttach,
|
---|
| 988 | g_pszPropAttachTemplate,
|
---|
| 989 | u32ActiveClientId);
|
---|
| 990 | if (l == -1)
|
---|
| 991 | {
|
---|
| 992 | pCtx->activeClient.pszPropAttach = NULL;
|
---|
| 993 | rc = VERR_NO_MEMORY;
|
---|
| 994 | }
|
---|
| 995 | }
|
---|
| 996 | }
|
---|
| 997 |
|
---|
| 998 | if (RT_SUCCESS(rc))
|
---|
| 999 | {
|
---|
| 1000 | if (pCtx->activeClient.pszPropWaitPattern)
|
---|
| 1001 | {
|
---|
| 1002 | RTMemFree(pCtx->activeClient.pszPropWaitPattern);
|
---|
| 1003 | pCtx->activeClient.pszPropWaitPattern = NULL;
|
---|
| 1004 | }
|
---|
| 1005 | if (u32ActiveClientId != 0)
|
---|
| 1006 | {
|
---|
| 1007 | l = RTStrAPrintf(&pCtx->activeClient.pszPropWaitPattern,
|
---|
[43584] | 1008 | "%s|%s|%s|%s|%s",
|
---|
[40498] | 1009 | pCtx->activeClient.pszPropName,
|
---|
[43584] | 1010 | pCtx->activeClient.pszPropAttach,
|
---|
| 1011 | pCtx->activeClient.pszPropIPAddr,
|
---|
| 1012 | pCtx->activeClient.pszPropLocation,
|
---|
| 1013 | pCtx->activeClient.pszPropOtherInfo);
|
---|
[40498] | 1014 | if (l == -1)
|
---|
| 1015 | {
|
---|
| 1016 | pCtx->activeClient.pszPropWaitPattern = NULL;
|
---|
| 1017 | rc = VERR_NO_MEMORY;
|
---|
| 1018 | }
|
---|
| 1019 | }
|
---|
| 1020 | }
|
---|
| 1021 |
|
---|
| 1022 | if (RT_SUCCESS(rc))
|
---|
| 1023 | {
|
---|
| 1024 | pCtx->activeClient.u32ClientId = u32ActiveClientId;
|
---|
| 1025 | }
|
---|
| 1026 | else
|
---|
| 1027 | {
|
---|
| 1028 | pCtx->activeClient.u32ClientId = 0;
|
---|
| 1029 | }
|
---|
| 1030 |
|
---|
[57741] | 1031 | LogFlowFunc(("laUpdateCurrentState rc = %Rrc\n", rc));
|
---|
[40498] | 1032 | return rc;
|
---|
| 1033 | }
|
---|
| 1034 |
|
---|
[57741] | 1035 | static int laWait(PVBOXLACONTEXT pCtx, uint64_t *pu64Timestamp, uint32_t u32Timeout)
|
---|
[40498] | 1036 | {
|
---|
[57741] | 1037 | LogFlowFunc(("laWait [%s]\n", pCtx->activeClient.pszPropWaitPattern));
|
---|
[40498] | 1038 |
|
---|
| 1039 | int rc = laWaitProperties(pCtx->u32GuestPropHandle,
|
---|
| 1040 | pCtx->activeClient.pszPropWaitPattern,
|
---|
| 1041 | pCtx->u64LastQuery,
|
---|
| 1042 | pu64Timestamp,
|
---|
| 1043 | u32Timeout);
|
---|
| 1044 |
|
---|
[57741] | 1045 | LogFlowFunc(("laWait rc %Rrc\n", rc));
|
---|
[40498] | 1046 | return rc;
|
---|
| 1047 | }
|
---|
| 1048 |
|
---|
[57741] | 1049 | static void laProcessClientInfo(PVBOXLACONTEXT pCtx)
|
---|
[40498] | 1050 | {
|
---|
| 1051 | /* Check if the name was changed. */
|
---|
| 1052 | /* Get the name string and check if it was changed since last time.
|
---|
[43584] | 1053 | * Write Client name, IPAddr, Location and Other Info to the registry if the name has changed.
|
---|
[40498] | 1054 | */
|
---|
| 1055 | uint64_t u64Timestamp = 0;
|
---|
[43584] | 1056 | int rc = VINF_SUCCESS;
|
---|
| 1057 | unsigned int idx;
|
---|
[40498] | 1058 |
|
---|
[43584] | 1059 | char *pClientInfoMap[][2] = {
|
---|
| 1060 | {pCtx->activeClient.pszPropName, NULL},
|
---|
| 1061 | {pCtx->activeClient.pszPropIPAddr, NULL},
|
---|
| 1062 | {pCtx->activeClient.pszPropLocation, NULL},
|
---|
| 1063 | {pCtx->activeClient.pszPropOtherInfo, NULL}
|
---|
| 1064 | };
|
---|
| 1065 |
|
---|
| 1066 | for (idx = 0; idx <= LA_UTCINFO_CLIENT_INFO_LAST; idx++)
|
---|
| 1067 | {
|
---|
| 1068 | rc = laGetString(pCtx->u32GuestPropHandle,
|
---|
| 1069 | pClientInfoMap[idx][LA_UTCINFO_PROP_NAME],
|
---|
[40498] | 1070 | &u64Timestamp,
|
---|
[43584] | 1071 | &pClientInfoMap[idx][LA_UTCINFO_PROP_VALUE]);
|
---|
| 1072 |
|
---|
[57741] | 1073 | LogFlowFunc(("laProcessClientInfo: read [%s], at %RU64\n",
|
---|
| 1074 | pClientInfoMap[idx][LA_UTCINFO_PROP_VALUE], u64Timestamp));
|
---|
[43584] | 1075 |
|
---|
| 1076 | if (RT_FAILURE(rc))
|
---|
| 1077 | {
|
---|
[51469] | 1078 | LogFlowFunc(("laProcessClientInfo failed at %s\n", pClientInfoMap[idx][LA_UTCINFO_PROP_NAME]));
|
---|
[43584] | 1079 | break;
|
---|
| 1080 | }
|
---|
| 1081 | }
|
---|
| 1082 |
|
---|
| 1083 | if (pClientInfoMap[LA_UTCINFO_CLIENT_NAME][LA_UTCINFO_PROP_VALUE] != NULL)
|
---|
[40498] | 1084 | {
|
---|
| 1085 | if (u64Timestamp != pCtx->activeClient.u64LastNameTimestamp)
|
---|
| 1086 | {
|
---|
[57741] | 1087 | laOnClientLocationInfo(pCtx, pClientInfoMap);
|
---|
[40498] | 1088 |
|
---|
| 1089 | pCtx->activeClient.u64LastNameTimestamp = u64Timestamp;
|
---|
| 1090 | }
|
---|
| 1091 | }
|
---|
| 1092 |
|
---|
[43584] | 1093 | for (idx = 0; idx <= LA_UTCINFO_CLIENT_INFO_LAST; idx++)
|
---|
[40498] | 1094 | {
|
---|
[43584] | 1095 | if (pClientInfoMap[idx][LA_UTCINFO_PROP_VALUE])
|
---|
| 1096 | {
|
---|
| 1097 | RTMemFree(pClientInfoMap[idx][LA_UTCINFO_PROP_VALUE]);
|
---|
| 1098 | }
|
---|
[40498] | 1099 | }
|
---|
| 1100 | }
|
---|
| 1101 |
|
---|
[57741] | 1102 | static void laProcessAttach(PVBOXLACONTEXT pCtx)
|
---|
[40498] | 1103 | {
|
---|
| 1104 | /* Check if the attach was changed. */
|
---|
| 1105 | pCtx->u32Action = LA_DO_NOTHING;
|
---|
| 1106 |
|
---|
| 1107 | uint64_t u64Timestamp = 0;
|
---|
[63104] | 1108 | uint32_t u32Attach = UINT32_MAX;
|
---|
[40498] | 1109 |
|
---|
| 1110 | int rc = laGetUint32(pCtx->u32GuestPropHandle,
|
---|
| 1111 | pCtx->activeClient.pszPropAttach,
|
---|
| 1112 | &u64Timestamp,
|
---|
| 1113 | &u32Attach);
|
---|
| 1114 |
|
---|
| 1115 | if (RT_SUCCESS(rc))
|
---|
| 1116 | {
|
---|
[57741] | 1117 | LogFlowFunc(("laProcessAttach: read %RU32, at %RU64\n", u32Attach, u64Timestamp));
|
---|
[40498] | 1118 | if (u64Timestamp != pCtx->activeClient.u64LastAttachTimestamp)
|
---|
| 1119 | {
|
---|
| 1120 | if (u32Attach != pCtx->activeClient.u32LastAttach)
|
---|
| 1121 | {
|
---|
[51469] | 1122 | LogFlowFunc(("laProcessAttach: changed\n"));
|
---|
[40498] | 1123 |
|
---|
| 1124 | /* Just do the last action. */
|
---|
[57741] | 1125 | pCtx->u32Action = u32Attach
|
---|
| 1126 | ? LA_DO_ATTACH : LA_DO_DETACH;
|
---|
[40498] | 1127 |
|
---|
| 1128 | pCtx->activeClient.u32LastAttach = u32Attach;
|
---|
| 1129 | }
|
---|
| 1130 | else
|
---|
| 1131 | {
|
---|
[51469] | 1132 | LogFlowFunc(("laProcessAttach: same\n"));
|
---|
[40498] | 1133 |
|
---|
| 1134 | /* The property has changed but the value is the same,
|
---|
| 1135 | * which means that it was changed and restored.
|
---|
| 1136 | */
|
---|
[57741] | 1137 | pCtx->u32Action = u32Attach
|
---|
| 1138 | ? LA_DO_DETACH_AND_ATTACH : LA_DO_ATTACH_AND_DETACH;
|
---|
[40498] | 1139 | }
|
---|
| 1140 |
|
---|
| 1141 | pCtx->activeClient.u64LastAttachTimestamp = u64Timestamp;
|
---|
| 1142 | }
|
---|
| 1143 |
|
---|
| 1144 | }
|
---|
| 1145 |
|
---|
[57741] | 1146 | LogFlowFunc(("laProcessAttach: action %RU32\n", pCtx->u32Action));
|
---|
[40498] | 1147 | }
|
---|
| 1148 |
|
---|
[57741] | 1149 | static void laDoActions(PVBOXLACONTEXT pCtx)
|
---|
[40498] | 1150 | {
|
---|
[57741] | 1151 | /*
|
---|
| 1152 | * Check if the attach was changed.
|
---|
[40498] | 1153 | *
|
---|
| 1154 | * Caller assumes that this function will filter double actions.
|
---|
| 1155 | * That is two or more LA_DO_ATTACH will do just one LA_DO_ATTACH.
|
---|
| 1156 | */
|
---|
[57741] | 1157 | LogFlowFunc(("laDoActions: action %RU32, prev %RU32\n", pCtx->u32Action, pCtx->u32PrevAction));
|
---|
[40498] | 1158 |
|
---|
| 1159 | switch(pCtx->u32Action)
|
---|
| 1160 | {
|
---|
| 1161 | case LA_DO_ATTACH:
|
---|
| 1162 | {
|
---|
| 1163 | if (pCtx->u32PrevAction != LA_DO_ATTACH)
|
---|
| 1164 | {
|
---|
| 1165 | pCtx->u32PrevAction = LA_DO_ATTACH;
|
---|
| 1166 | laDoAttach(pCtx);
|
---|
| 1167 | }
|
---|
| 1168 | } break;
|
---|
| 1169 |
|
---|
| 1170 | case LA_DO_DETACH:
|
---|
| 1171 | {
|
---|
| 1172 | if (pCtx->u32PrevAction != LA_DO_DETACH)
|
---|
| 1173 | {
|
---|
| 1174 | pCtx->u32PrevAction = LA_DO_DETACH;
|
---|
| 1175 | laDoDetach(pCtx);
|
---|
| 1176 | }
|
---|
| 1177 | } break;
|
---|
| 1178 |
|
---|
| 1179 | case LA_DO_DETACH_AND_ATTACH:
|
---|
| 1180 | {
|
---|
| 1181 | if (pCtx->u32PrevAction != LA_DO_DETACH)
|
---|
| 1182 | {
|
---|
| 1183 | pCtx->u32PrevAction = LA_DO_DETACH;
|
---|
| 1184 | laDoDetach(pCtx);
|
---|
| 1185 | }
|
---|
| 1186 | pCtx->u32PrevAction = LA_DO_ATTACH;
|
---|
| 1187 | laDoAttach(pCtx);
|
---|
| 1188 | } break;
|
---|
| 1189 |
|
---|
| 1190 | case LA_DO_ATTACH_AND_DETACH:
|
---|
| 1191 | {
|
---|
| 1192 | if (pCtx->u32PrevAction != LA_DO_ATTACH)
|
---|
| 1193 | {
|
---|
| 1194 | pCtx->u32PrevAction = LA_DO_ATTACH;
|
---|
| 1195 | laDoAttach(pCtx);
|
---|
| 1196 | }
|
---|
| 1197 | pCtx->u32PrevAction = LA_DO_DETACH;
|
---|
| 1198 | laDoDetach(pCtx);
|
---|
| 1199 | } break;
|
---|
| 1200 |
|
---|
| 1201 | case LA_DO_NOTHING:
|
---|
| 1202 | default:
|
---|
| 1203 | break;
|
---|
| 1204 | }
|
---|
| 1205 |
|
---|
| 1206 | pCtx->u32Action = LA_DO_NOTHING;
|
---|
| 1207 |
|
---|
[51469] | 1208 | LogFlowFunc(("laDoActions: leave\n"));
|
---|
[40498] | 1209 | }
|
---|
| 1210 |
|
---|
[57741] | 1211 | DECLCALLBACK(int) VBoxLAInit(const PVBOXSERVICEENV pEnv, void **ppInstance)
|
---|
[40498] | 1212 | {
|
---|
[57741] | 1213 | AssertPtrReturn(pEnv, VERR_INVALID_POINTER);
|
---|
| 1214 | AssertPtrReturn(ppInstance, VERR_INVALID_POINTER);
|
---|
[40797] | 1215 |
|
---|
[57741] | 1216 | LogFlowFuncEnter();
|
---|
| 1217 |
|
---|
| 1218 | PVBOXLACONTEXT pCtx = &g_Ctx; /* Only one instance at the moment. */
|
---|
| 1219 | AssertPtr(pCtx);
|
---|
| 1220 |
|
---|
| 1221 | pCtx->pEnv = pEnv;
|
---|
| 1222 |
|
---|
[40797] | 1223 | DWORD dwValue = 0;
|
---|
| 1224 | if ( laGetRegistryDWORD(L"SOFTWARE\\Oracle\\VirtualBox Guest Additions", L"VBoxTrayLog", &dwValue)
|
---|
| 1225 | && (dwValue & 0x10) != 0)
|
---|
| 1226 | {
|
---|
[57741] | 1227 | pCtx->fLogEnabled = true;
|
---|
[40797] | 1228 | }
|
---|
| 1229 | else
|
---|
| 1230 | {
|
---|
[57741] | 1231 | pCtx->fLogEnabled = false;
|
---|
[40797] | 1232 | }
|
---|
| 1233 |
|
---|
[40891] | 1234 | /* DetachOnDisconnect is enabled by default. */
|
---|
| 1235 | dwValue = 0x02;
|
---|
[40866] | 1236 | if ( laGetRegistryDWORD(L"SOFTWARE\\Oracle\\VirtualBox Guest Additions", L"VBoxTrayLA", &dwValue)
|
---|
[40891] | 1237 | && (dwValue & 0x02) == 0)
|
---|
[40866] | 1238 | {
|
---|
[57741] | 1239 | pCtx->fDetachOnDisconnect = false;
|
---|
[40866] | 1240 | }
|
---|
| 1241 | else
|
---|
| 1242 | {
|
---|
[57741] | 1243 | pCtx->fDetachOnDisconnect = true;
|
---|
[40866] | 1244 | }
|
---|
| 1245 |
|
---|
[57741] | 1246 | LogRel(("LA: DetachOnDisconnect=%RTbool\n", pCtx->fDetachOnDisconnect));
|
---|
[40866] | 1247 |
|
---|
[57741] | 1248 | int rc = VbglR3GuestPropConnect(&pCtx->u32GuestPropHandle);
|
---|
[40498] | 1249 | if (RT_FAILURE(rc))
|
---|
| 1250 | return rc;
|
---|
| 1251 |
|
---|
[57741] | 1252 | RTListInit(&pCtx->listAttachActions);
|
---|
| 1253 | RTListInit(&pCtx->listDetachActions);
|
---|
[40498] | 1254 |
|
---|
[57741] | 1255 | RT_ZERO(pCtx->activeClient);
|
---|
[40498] | 1256 |
|
---|
[57741] | 1257 | *(void **)&pCtx->pfnProcessIdToSessionId = RTLdrGetSystemSymbol("kernel32.dll", "ProcessIdToSessionId");
|
---|
| 1258 |
|
---|
| 1259 | *ppInstance = pCtx;
|
---|
| 1260 | LogFlowFuncLeaveRC(VINF_SUCCESS);
|
---|
[40498] | 1261 | return VINF_SUCCESS;
|
---|
| 1262 | }
|
---|
| 1263 |
|
---|
[57741] | 1264 | DECLCALLBACK(void) VBoxLADestroy(void *pInstance)
|
---|
[40498] | 1265 | {
|
---|
[57741] | 1266 | AssertPtrReturnVoid(pInstance);
|
---|
[40498] | 1267 |
|
---|
[57741] | 1268 | LogFlowFunc(("Destroying pInstance=%p\n", pInstance));
|
---|
[40498] | 1269 |
|
---|
[57741] | 1270 | PVBOXLACONTEXT pCtx = (PVBOXLACONTEXT)pInstance;
|
---|
| 1271 | AssertPtr(pCtx);
|
---|
| 1272 |
|
---|
[40498] | 1273 | if (pCtx->u32GuestPropHandle != 0)
|
---|
| 1274 | {
|
---|
| 1275 | VbglR3GuestPropDisconnect(pCtx->u32GuestPropHandle);
|
---|
| 1276 | }
|
---|
| 1277 |
|
---|
| 1278 | ActionExecutorDeleteActions(&pCtx->listAttachActions);
|
---|
| 1279 | ActionExecutorDeleteActions(&pCtx->listDetachActions);
|
---|
| 1280 |
|
---|
[46593] | 1281 | pCtx->pfnProcessIdToSessionId = NULL;
|
---|
[40498] | 1282 | }
|
---|
| 1283 |
|
---|
| 1284 | /*
|
---|
| 1285 | * Thread function to wait for and process property changes
|
---|
| 1286 | */
|
---|
[57741] | 1287 | DECLCALLBACK(int) VBoxLAWorker(void *pInstance, bool volatile *pfShutdown)
|
---|
[40498] | 1288 | {
|
---|
[57741] | 1289 | AssertPtr(pInstance);
|
---|
| 1290 | LogFlowFunc(("pInstance=%p\n", pInstance));
|
---|
[40498] | 1291 |
|
---|
[57741] | 1292 | /*
|
---|
| 1293 | * Tell the control thread that it can continue
|
---|
| 1294 | * spawning services.
|
---|
| 1295 | */
|
---|
| 1296 | RTThreadUserSignal(RTThreadSelf());
|
---|
[40498] | 1297 |
|
---|
[57741] | 1298 | PVBOXLACONTEXT pCtx = (PVBOXLACONTEXT)pInstance;
|
---|
| 1299 |
|
---|
[40498] | 1300 | /*
|
---|
| 1301 | * On name change event (/VirtualBox/HostInfo/VRDP/Client/%ID%/Name)
|
---|
| 1302 | * Store the name in the registry (HKCU\Volatile Environment\UTCINFO_CLIENTNAME).
|
---|
| 1303 | * On a client attach event (/VirtualBox/HostInfo/VRDP/Client/%ID%/Attach -> 1):
|
---|
| 1304 | * Execute ReconnectActions
|
---|
| 1305 | * On a client detach event (/VirtualBox/HostInfo/VRDP/Client/%ID%/Attach -> 0):
|
---|
| 1306 | * Execute DisconnectActions
|
---|
| 1307 | *
|
---|
| 1308 | * The active connected client id is /VirtualBox/HostInfo/VRDP/ActiveClientClient.
|
---|
| 1309 | */
|
---|
| 1310 |
|
---|
[57741] | 1311 | if (!ActionExecutorEnumerateRegistryKey(g_pwszRegKeyReconnectActions, &pCtx->listAttachActions))
|
---|
[40498] | 1312 | {
|
---|
[51469] | 1313 | LogFlowFunc(("Can't enumerate registry key %ls\n", g_pwszRegKeyReconnectActions));
|
---|
[40498] | 1314 | }
|
---|
[57741] | 1315 | if (!ActionExecutorEnumerateRegistryKey(g_pwszRegKeyDisconnectActions, &pCtx->listDetachActions))
|
---|
[40498] | 1316 | {
|
---|
[51469] | 1317 | LogFlowFunc(("Can't enumerate registry key %ls\n", g_pwszRegKeyDisconnectActions));
|
---|
[40498] | 1318 | }
|
---|
| 1319 |
|
---|
| 1320 | /* A non zero timestamp in the past. */
|
---|
| 1321 | pCtx->u64LastQuery = 1;
|
---|
| 1322 | /* Start at Detached state. */
|
---|
| 1323 | pCtx->u32PrevAction = LA_DO_DETACH;
|
---|
| 1324 |
|
---|
[57741] | 1325 | int rc;
|
---|
| 1326 |
|
---|
[40498] | 1327 | for (;;)
|
---|
| 1328 | {
|
---|
| 1329 | /* Query current ActiveClient.
|
---|
| 1330 | * if it differs from the current active client
|
---|
| 1331 | * rebuild the context;
|
---|
| 1332 | * wait with timeout for properties change since the active client was changed;
|
---|
| 1333 | * if 'Name' was changed
|
---|
| 1334 | * update the name;
|
---|
| 1335 | * if 'Attach' was changed
|
---|
| 1336 | * do respective actions.
|
---|
| 1337 | * remember the query timestamp;
|
---|
| 1338 | */
|
---|
| 1339 | uint64_t u64Timestamp = 0;
|
---|
| 1340 | uint32_t u32ActiveClientId = 0;
|
---|
[57741] | 1341 | rc = laGetActiveClient(pCtx, &u64Timestamp, &u32ActiveClientId);
|
---|
[40498] | 1342 |
|
---|
| 1343 | if (RT_SUCCESS(rc))
|
---|
| 1344 | {
|
---|
[40863] | 1345 | bool fClientIdChanged = pCtx->activeClient.u32ClientId != u32ActiveClientId;
|
---|
| 1346 |
|
---|
| 1347 | if (fClientIdChanged)
|
---|
[40498] | 1348 | {
|
---|
| 1349 | rc = laUpdateCurrentState(pCtx, u32ActiveClientId, u64Timestamp);
|
---|
| 1350 | }
|
---|
| 1351 |
|
---|
| 1352 | if (RT_SUCCESS(rc))
|
---|
| 1353 | {
|
---|
| 1354 | if (pCtx->activeClient.u32ClientId != 0)
|
---|
| 1355 | {
|
---|
| 1356 | rc = laWait(pCtx, &u64Timestamp, 1000);
|
---|
| 1357 |
|
---|
| 1358 | if (RT_SUCCESS(rc))
|
---|
| 1359 | {
|
---|
| 1360 | laProcessAttach(pCtx);
|
---|
| 1361 |
|
---|
[43584] | 1362 | laProcessClientInfo(pCtx);
|
---|
[40498] | 1363 |
|
---|
| 1364 | laDoActions(pCtx);
|
---|
| 1365 |
|
---|
| 1366 | pCtx->u64LastQuery = u64Timestamp;
|
---|
| 1367 | }
|
---|
| 1368 | }
|
---|
[40863] | 1369 | else
|
---|
| 1370 | {
|
---|
| 1371 | /* If the client has been disconnected, do the detach actions. */
|
---|
[40866] | 1372 | if ( pCtx->fDetachOnDisconnect
|
---|
| 1373 | && fClientIdChanged)
|
---|
[40863] | 1374 | {
|
---|
[57741] | 1375 | LogFlowFunc(("Client disconnected\n"));
|
---|
[40863] | 1376 |
|
---|
| 1377 | /* laDoActions will prevent a repeated detach action. So if there
|
---|
| 1378 | * was a detach already, then this detach will be ignored.
|
---|
| 1379 | */
|
---|
| 1380 | pCtx->u32Action = LA_DO_DETACH;
|
---|
| 1381 |
|
---|
| 1382 | laDoActions(pCtx);
|
---|
| 1383 |
|
---|
| 1384 | pCtx->u64LastQuery = u64Timestamp;
|
---|
| 1385 | }
|
---|
| 1386 | }
|
---|
[40498] | 1387 | }
|
---|
| 1388 | }
|
---|
| 1389 |
|
---|
[57741] | 1390 | /*
|
---|
| 1391 | * Check if it is time to exit.
|
---|
[40498] | 1392 | * If the code above failed, wait a bit until repeating to avoid a loop.
|
---|
| 1393 | * Otherwise just check if the stop event was signalled.
|
---|
| 1394 | */
|
---|
[57741] | 1395 | RTMSINTERVAL msWait;
|
---|
[40498] | 1396 | if ( rc == VERR_NOT_FOUND
|
---|
| 1397 | || pCtx->activeClient.u32ClientId == 0)
|
---|
| 1398 | {
|
---|
| 1399 | /* No connections, wait longer. */
|
---|
[57741] | 1400 | msWait = 5000;
|
---|
| 1401 | rc = VINF_SUCCESS;
|
---|
[40498] | 1402 | }
|
---|
| 1403 | else if (RT_FAILURE(rc))
|
---|
| 1404 | {
|
---|
[57741] | 1405 | static int s_iBitchedAboutFailedGetActiveClient = 0;
|
---|
| 1406 | if (s_iBitchedAboutFailedGetActiveClient++ < 32)
|
---|
| 1407 | LogRel(("LA: Retrieving current client(s) failed with %Rrc\n", rc));
|
---|
| 1408 |
|
---|
| 1409 | msWait = 10000;
|
---|
[40498] | 1410 | }
|
---|
| 1411 | else
|
---|
[57741] | 1412 | msWait = 0;
|
---|
| 1413 |
|
---|
| 1414 | if (*pfShutdown)
|
---|
[40498] | 1415 | break;
|
---|
[57741] | 1416 |
|
---|
| 1417 | if (msWait)
|
---|
| 1418 | RTThreadSleep(msWait);
|
---|
[40498] | 1419 | }
|
---|
| 1420 |
|
---|
[57741] | 1421 | LogFlowFuncLeaveRC(rc);
|
---|
| 1422 | return rc;
|
---|
[40498] | 1423 | }
|
---|
[57741] | 1424 |
|
---|
| 1425 | /**
|
---|
| 1426 | * The service description.
|
---|
| 1427 | */
|
---|
| 1428 | VBOXSERVICEDESC g_SvcDescLA =
|
---|
| 1429 | {
|
---|
| 1430 | /* pszName. */
|
---|
| 1431 | "LA",
|
---|
| 1432 | /* pszDescription. */
|
---|
| 1433 | "Location Awareness",
|
---|
| 1434 | /* methods */
|
---|
| 1435 | VBoxLAInit,
|
---|
| 1436 | VBoxLAWorker,
|
---|
| 1437 | NULL /* pfnStop */,
|
---|
| 1438 | VBoxLADestroy
|
---|
| 1439 | };
|
---|
| 1440 |
|
---|