VirtualBox

source: vbox/trunk/src/VBox/Additions/common/VBoxService/VBoxServiceVMInfo.cpp@ 29391

Last change on this file since 29391 was 29391, checked in by vboxsync, 15 years ago

VBoxServiceVMInfo: Solaris build fix

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 22.4 KB
Line 
1/* $Id: VBoxServiceVMInfo.cpp 29391 2010-05-11 20:38:39Z vboxsync $ */
2/** @file
3 * VBoxService - Virtual Machine Information for the Host.
4 */
5
6/*
7 * Copyright (C) 2009-2010 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.virtualbox.org. This file is free software;
11 * you can redistribute it and/or modify it under the terms of the GNU
12 * General Public License (GPL) as published by the Free Software
13 * Foundation, in version 2 as it comes in the "COPYING" file of the
14 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
15 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
16 */
17
18
19
20/*******************************************************************************
21* Header Files *
22*******************************************************************************/
23#ifdef RT_OS_WINDOWS
24#include <winsock2.h>
25#include <ws2tcpip.h>
26#include <windows.h>
27#include <Ntsecapi.h>
28#else
29# define __STDC_LIMIT_MACROS
30# include <arpa/inet.h>
31# include <errno.h>
32# include <netinet/in.h>
33# include <sys/ioctl.h>
34# include <sys/socket.h>
35# include <net/if.h>
36# include <unistd.h>
37# ifndef RT_OS_FREEBSD /* The header does not exist anymore since FreeBSD 9-current */
38# include <utmp.h>
39# endif
40# ifdef RT_OS_SOLARIS
41# include <sys/sockio.h>
42# endif
43#endif
44
45#include <iprt/mem.h>
46#include <iprt/thread.h>
47#include <iprt/string.h>
48#include <iprt/semaphore.h>
49#include <iprt/system.h>
50#include <iprt/time.h>
51#include <iprt/assert.h>
52#include <VBox/version.h>
53#include <VBox/VBoxGuestLib.h>
54#include "VBoxServiceInternal.h"
55#include "VBoxServiceUtils.h"
56#include "VBoxServicePropCache.h"
57
58
59/*******************************************************************************
60* Global Variables *
61*******************************************************************************/
62/** The vminfo interval (millseconds). */
63static uint32_t g_cMsVMInfoInterval = 0;
64/** The semaphore we're blocking on. */
65static RTSEMEVENTMULTI g_hVMInfoEvent = NIL_RTSEMEVENTMULTI;
66/** The guest property service client ID. */
67static uint32_t g_uVMInfoGuestPropSvcClientID = 0;
68/** Number of logged in users in OS. */
69static uint32_t g_cVMInfoLoggedInUsers = UINT32_MAX;
70/** The guest property cache. */
71static VBOXSERVICEVEPROPCACHE g_VMInfoPropCache;
72
73
74/** @copydoc VBOXSERVICE::pfnPreInit */
75static DECLCALLBACK(int) VBoxServiceVMInfoPreInit(void)
76{
77 return VINF_SUCCESS;
78}
79
80
81/** @copydoc VBOXSERVICE::pfnOption */
82static DECLCALLBACK(int) VBoxServiceVMInfoOption(const char **ppszShort, int argc, char **argv, int *pi)
83{
84 int rc = -1;
85 if (ppszShort)
86 /* no short options */;
87 else if (!strcmp(argv[*pi], "--vminfo-interval"))
88 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
89 &g_cMsVMInfoInterval, 1, UINT32_MAX - 1);
90 return rc;
91}
92
93
94/** @copydoc VBOXSERVICE::pfnInit */
95static DECLCALLBACK(int) VBoxServiceVMInfoInit(void)
96{
97 /*
98 * If not specified, find the right interval default.
99 * Then create the event sem to block on.
100 */
101 if (!g_cMsVMInfoInterval)
102 g_cMsVMInfoInterval = g_DefaultInterval * 1000;
103 if (!g_cMsVMInfoInterval)
104 g_cMsVMInfoInterval = 10 * 1000;
105
106 int rc = RTSemEventMultiCreate(&g_hVMInfoEvent);
107 AssertRCReturn(rc, rc);
108
109#ifdef RT_OS_WINDOWS
110 /** @todo r=bird: call a windows specific init function and move
111 * g_pfnWTSGetActiveConsoleSessionId out of the global scope. */
112 /* Get function pointers. */
113 HMODULE hKernel32 = LoadLibrary("kernel32");
114 if (hKernel32 != NULL)
115 {
116 g_pfnWTSGetActiveConsoleSessionId = (PFNWTSGETACTIVECONSOLESESSIONID)GetProcAddress(hKernel32, "WTSGetActiveConsoleSessionId");
117 FreeLibrary(hKernel32);
118 }
119#endif
120
121 rc = VbglR3GuestPropConnect(&g_uVMInfoGuestPropSvcClientID);
122 if (RT_SUCCESS(rc))
123 VBoxServiceVerbose(3, "VMInfo: Property Service Client ID: %#x\n", g_uVMInfoGuestPropSvcClientID);
124 else
125 {
126 /* If the service was not found, we disable this service without
127 causing VBoxService to fail. */
128 if (rc == VERR_HGCM_SERVICE_NOT_FOUND) /* Host service is not available. */
129 {
130 VBoxServiceVerbose(0, "VMInfo: Guest property service is not available, disabling the service\n");
131 rc = VERR_SERVICE_DISABLED;
132 }
133 else
134 VBoxServiceError("VMInfo: Failed to connect to the guest property service! Error: %Rrc\n", rc);
135 RTSemEventMultiDestroy(g_hVMInfoEvent);
136 g_hVMInfoEvent = NIL_RTSEMEVENTMULTI;
137 }
138
139 if (RT_SUCCESS(rc))
140 {
141 VBoxServicePropCacheCreate(&g_VMInfoPropCache, g_uVMInfoGuestPropSvcClientID);
142
143 /*
144 * Declare some guest properties with flags and reset values.
145 */
146 VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList",
147 VBOXSERVICEPROPCACHEFLAG_TEMPORARY, NULL /* Delete on exit */);
148 VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsers",
149 VBOXSERVICEPROPCACHEFLAG_TEMPORARY, "0");
150 VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers",
151 VBOXSERVICEPROPCACHEFLAG_TEMPORARY, "true");
152 VBoxServicePropCacheUpdateEntry(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/Net/Count",
153 VBOXSERVICEPROPCACHEFLAG_TEMPORARY | VBOXSERVICEPROPCACHEFLAG_ALWAYS_UPDATE, NULL /* Delete on exit */);
154 }
155 return rc;
156}
157
158
159/**
160 * Writes the properties that won't change while the service is running.
161 *
162 * Errors are ignored.
163 */
164static void VBoxServiceVMInfoWriteFixedProperties(void)
165{
166 /*
167 * First get OS information that won't change.
168 */
169 char szInfo[256];
170 int rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szInfo, sizeof(szInfo));
171 VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Product",
172 "%s", RT_FAILURE(rc) ? "" : szInfo);
173
174 rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szInfo, sizeof(szInfo));
175 VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Release",
176 "%s", RT_FAILURE(rc) ? "" : szInfo);
177
178 rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szInfo, sizeof(szInfo));
179 VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/Version",
180 "%s", RT_FAILURE(rc) ? "" : szInfo);
181
182 rc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szInfo, sizeof(szInfo));
183 VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestInfo/OS/ServicePack",
184 "%s", RT_FAILURE(rc) ? "" : szInfo);
185
186 /*
187 * Retrieve version information about Guest Additions and installed files (components).
188 */
189 char *pszAddVer;
190 char *pszAddRev;
191 rc = VbglR3GetAdditionsVersion(&pszAddVer, &pszAddRev);
192 VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/Version",
193 "%s", RT_FAILURE(rc) ? "" : pszAddVer);
194 VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/Revision",
195 "%s", RT_FAILURE(rc) ? "" : pszAddRev);
196 if (RT_SUCCESS(rc))
197 {
198 RTStrFree(pszAddVer);
199 RTStrFree(pszAddRev);
200 }
201
202#ifdef RT_OS_WINDOWS
203 /*
204 * Do windows specific properties.
205 */
206 char *pszInstDir;
207 rc = VbglR3GetAdditionsInstallationPath(&pszInstDir);
208 VBoxServiceWritePropF(g_uVMInfoGuestPropSvcClientID, "/VirtualBox/GuestAdd/InstallDir",
209 "%s", RT_FAILURE(rc) ? "" : pszInstDir);
210 if (RT_SUCCESS(rc))
211 RTStrFree(pszInstDir);
212
213 VBoxServiceWinGetComponentVersions(g_uVMInfoGuestPropSvcClientID);
214#endif
215}
216
217
218/**
219 * Provide information about active users.
220 */
221int VBoxServiceVMInfoWriteUsers()
222{
223 int rc;
224 char szUserList[4096] = {0};
225 uint32_t cUsersInList = 0;
226
227#ifdef RT_OS_WINDOWS
228# ifndef TARGET_NT4
229 PLUID paSessions = NULL;
230 ULONG cSession = 0;
231 NTSTATUS r = 0;
232
233 /* This function can report stale or orphaned interactive logon sessions
234 of already logged off users (especially in Windows 2000). */
235 r = ::LsaEnumerateLogonSessions(&cSession, &paSessions);
236 VBoxServiceVerbose(3, "Users: Found %ld users.\n", cSession);
237 if (r != STATUS_SUCCESS)
238 {
239 VBoxServiceError("LsaEnumerate failed %lu\n", LsaNtStatusToWinError(r));
240 return RTErrConvertFromWin32(LsaNtStatusToWinError(r));
241 }
242
243 PVBOXSERVICEVMINFOPROC paProcs;
244 DWORD cProcs;
245 rc = VBoxServiceVMInfoWinProcessesEnumerate(&paProcs, &cProcs);
246 if (RT_SUCCESS(rc))
247 {
248 for (ULONG i = 0; i < cSession; i++)
249 {
250 VBOXSERVICEVMINFOUSER UserInfo;
251 if ( VBoxServiceVMInfoWinIsLoggedIn(&UserInfo, &paSessions[i])
252 && VBoxServiceVMInfoWinSessionHasProcesses(&paSessions[i], paProcs, cProcs))
253 {
254 if (cUsersInList > 0)
255 strcat(szUserList, ",");
256
257 cUsersInList++;
258
259 char *pszTemp;
260 int rc2 = RTUtf16ToUtf8(UserInfo.wszUser, &pszTemp);
261 if (RT_SUCCESS(rc2))
262 {
263 strcat(szUserList, pszTemp);
264 RTMemFree(pszTemp);
265 }
266 else
267 strcat(szUserList, "<string-convertion-error>");
268 }
269 }
270 VBoxServiceVMInfoWinProcessesFree(paProcs);
271 }
272
273 ::LsaFreeReturnBuffer(paSessions);
274# endif /* TARGET_NT4 */
275#elif defined(RT_OS_FREEBSD)
276 /** @todo FreeBSD: Port logged on user info retrival. */
277#elif defined(RT_OS_OS2)
278 /** @todo OS/2: Port logged on (LAN/local/whatever) user info retrival. */
279#else
280 rc = utmpname(UTMP_FILE);
281# ifdef RT_OS_SOLARIS
282 if (rc != 1)
283# else
284 if (rc != 0)
285# endif
286 {
287 VBoxServiceError("Could not set UTMP file! Error: %ld\n", errno);
288 }
289 setutent();
290 utmp *ut_user;
291 while ((ut_user = getutent()))
292 {
293 /* Make sure we don't add user names which are not
294 * part of type USER_PROCESS and don't add same users twice. */
295 if ( ut_user->ut_type == USER_PROCESS
296 && strstr(szUserList, ut_user->ut_user) == NULL)
297 {
298 /** @todo Do we really want to filter out double user names? (Same user logged in twice)
299 * bird: If we do, then we must add checks for buffer overflows here! */
300 /** @todo r=bird: strstr will filtering out users with similar names. For
301 * example: smith, smithson, joesmith and bobsmith */
302 if (cUsersInList > 0)
303 strcat(szUserList, ",");
304 strcat(szUserList, ut_user->ut_user);
305 cUsersInList++;
306 }
307 }
308 endutent();
309#endif /* !RT_OS_WINDOWS */
310
311 if (cUsersInList > 0)
312 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", "%s", szUserList);
313 else
314 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsersList", NULL);
315 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/LoggedInUsers", "%u", cUsersInList);
316 if ( g_cVMInfoLoggedInUsers != cUsersInList
317 || g_cVMInfoLoggedInUsers == UINT32_MAX)
318 {
319 /*
320 * Update this property ONLY if there is a real change from no users to
321 * users or vice versa. The only exception is that the initialization
322 * forces an update, but only once. This ensures consistent property
323 * settings even if the VM aborted previously.
324 */
325 if (cUsersInList == 0)
326 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers", "true");
327 else if (g_cVMInfoLoggedInUsers == 0)
328 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/OS/NoLoggedInUsers", "false");
329 }
330 g_cVMInfoLoggedInUsers = cUsersInList;
331
332 return VINF_SUCCESS;
333}
334
335
336/**
337 * Provide information about the guest network.
338 */
339int VBoxServiceVMInfoWriteNetwork()
340{
341 int cIfacesReport = 0;
342 char szPropPath [FILENAME_MAX];
343
344#ifdef RT_OS_WINDOWS
345 SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
346 if (sd == SOCKET_ERROR) /* Socket invalid. */
347 {
348 VBoxServiceError("Failed to get a socket: Error %d\n", WSAGetLastError());
349 return RTErrConvertFromWin32(WSAGetLastError());
350 }
351
352 INTERFACE_INFO InterfaceList[20] = {0};
353 unsigned long nBytesReturned = 0;
354 if (WSAIoctl(sd,
355 SIO_GET_INTERFACE_LIST,
356 0,
357 0,
358 &InterfaceList,
359 sizeof(InterfaceList),
360 &nBytesReturned,
361 0,
362 0) == SOCKET_ERROR)
363 {
364 VBoxServiceError("Failed to WSAIoctl() on socket: Error: %d\n", WSAGetLastError());
365 return RTErrConvertFromWin32(WSAGetLastError());
366 }
367 int cIfacesSystem = nBytesReturned / sizeof(INTERFACE_INFO);
368
369 /** @todo Use GetAdaptersInfo() and GetAdapterAddresses (IPv4 + IPv6) for more information. */
370 for (int i = 0; i < cIfacesSystem; ++i)
371 {
372 sockaddr_in *pAddress;
373 u_long nFlags = 0;
374 if (InterfaceList[i].iiFlags & IFF_LOOPBACK) /* Skip loopback device. */
375 continue;
376 nFlags = InterfaceList[i].iiFlags;
377 pAddress = (sockaddr_in *)&(InterfaceList[i].iiAddress);
378 Assert(pAddress);
379 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/V4/IP", cIfacesReport);
380 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
381
382 pAddress = (sockaddr_in *) & (InterfaceList[i].iiBroadcastAddress);
383 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/V4/Broadcast", cIfacesReport);
384 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
385
386 pAddress = (sockaddr_in *)&(InterfaceList[i].iiNetmask);
387 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/V4/Netmask", cIfacesReport);
388 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
389
390 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/Status", cIfacesReport);
391 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, nFlags & IFF_UP ? "Up" : "Down");
392 cIfacesReport++;
393 }
394 if (sd >= 0)
395 closesocket(sd);
396#else /* !RT_OS_WINDOWS */
397 int sd = socket(AF_INET, SOCK_DGRAM, 0);
398 if (sd < 0)
399 {
400 VBoxServiceError("Failed to get a socket: Error %d\n", errno);
401 return RTErrConvertFromErrno(errno);
402 }
403
404 ifconf ifcfg;
405 char buffer[1024] = {0};
406 ifcfg.ifc_len = sizeof(buffer);
407 ifcfg.ifc_buf = buffer;
408 if (ioctl(sd, SIOCGIFCONF, &ifcfg) < 0)
409 {
410 VBoxServiceError("Failed to ioctl(SIOCGIFCONF) on socket: Error %d\n", errno);
411 return RTErrConvertFromErrno(errno);
412 }
413
414 ifreq* ifrequest = ifcfg.ifc_req;
415 int cIfacesSystem = ifcfg.ifc_len / sizeof(ifreq);
416
417 for (int i = 0; i < cIfacesSystem; ++i)
418 {
419 sockaddr_in *pAddress;
420 if (ioctl(sd, SIOCGIFFLAGS, &ifrequest[i]) < 0)
421 {
422 VBoxServiceError("Failed to ioctl(SIOCGIFFLAGS) on socket: Error %d\n", errno);
423 close(sd);
424 return RTErrConvertFromErrno(errno);
425 }
426 if (ifrequest[i].ifr_flags & IFF_LOOPBACK) /* Skip the loopback device. */
427 continue;
428
429 bool fIfUp = !!(ifrequest[i].ifr_flags & IFF_UP);
430 pAddress = ((sockaddr_in *)&ifrequest[i].ifr_addr);
431 Assert(pAddress);
432 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/V4/IP", cIfacesReport);
433 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
434
435 if (ioctl(sd, SIOCGIFBRDADDR, &ifrequest[i]) < 0)
436 {
437 VBoxServiceError("Failed to ioctl(SIOCGIFBRDADDR) on socket: Error %d\n", errno);
438 close(sd);
439 return RTErrConvertFromErrno(errno);
440 }
441 pAddress = (sockaddr_in *)&ifrequest[i].ifr_broadaddr;
442 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/V4/Broadcast", cIfacesReport);
443 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
444
445 if (ioctl(sd, SIOCGIFNETMASK, &ifrequest[i]) < 0)
446 {
447 VBoxServiceError("Failed to ioctl(SIOCGIFBRDADDR) on socket: Error %d\n", errno);
448 close(sd);
449 return RTErrConvertFromErrno(errno);
450 }
451 #if defined(RT_OS_FREEBSD) || defined(RT_OS_OS2) || defined(RT_OS_SOLARIS)
452 pAddress = (sockaddr_in *)&ifrequest[i].ifr_addr;
453 #else
454 pAddress = (sockaddr_in *)&ifrequest[i].ifr_netmask;
455 #endif
456
457 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/V4/Netmask", cIfacesReport);
458 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", inet_ntoa(pAddress->sin_addr));
459
460 #if defined(RT_OS_SOLARIS)
461 if (ioctl(sd, SIOCGENADDR, &ifrequest[i]) < 0)
462 #else
463 if (ioctl(sd, SIOCGIFHWADDR, &ifrequest[i]) < 0)
464 #endif
465 {
466 VBoxServiceError("Failed to ioctl(SIOCGIFHWADDR) on socket: Error %d\n", errno);
467 close(sd);
468 return RTErrConvertFromErrno(errno);
469 }
470
471 char szMac[32];
472 #if defined(RT_OS_SOLARIS)
473 char *pu8Mac = &ifrequest[i].ifr_enaddr[0];
474 #else
475 char *pu8Mac = &ifrequest[i].ifr_hwaddr.sa_data[0];
476 #endif
477 RTStrPrintf(szMac, sizeof(szMac), "%02x:%02x:%02x:%02x:%02x:%02x",
478 pu8Mac[0], pu8Mac[1], pu8Mac[2], pu8Mac[3], pu8Mac[4], pu8Mac[5]);
479 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/MAC", cIfacesReport);
480 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, "%s", szMac);
481
482 RTStrPrintf(szPropPath, sizeof(szPropPath), "/VirtualBox/GuestInfo/Net/%d/Status", cIfacesReport);
483 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, szPropPath, fIfUp ? "Up" : "Down");
484 cIfacesReport++;
485 }
486
487 close(sd);
488
489#endif /* !RT_OS_WINDOWS */
490
491 /*
492 * This property is a beacon which is _always_ written, even if the network configuration
493 * does not change. If this property is missing, the host assumes that all other GuestInfo
494 * properties are no longer valid.
495 */
496 VBoxServicePropCacheUpdate(&g_VMInfoPropCache, "/VirtualBox/GuestInfo/Net/Count", "%d",
497 cIfacesReport);
498
499 /** @todo r=bird: if cIfacesReport decreased compared to the previous run, zap
500 * the stale data. This can probably be encorporated into the cache. */
501
502 return VINF_SUCCESS;
503}
504
505
506/** @copydoc VBOXSERVICE::pfnWorker */
507DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown)
508{
509 int rc;
510
511 /*
512 * Tell the control thread that it can continue
513 * spawning services.
514 */
515 RTThreadUserSignal(RTThreadSelf());
516
517#ifdef RT_OS_WINDOWS
518 /* Required for network information (must be called per thread). */
519 WSADATA wsaData;
520 if (WSAStartup(MAKEWORD(2, 2), &wsaData))
521 VBoxServiceError("WSAStartup failed! Error: %Rrc\n", RTErrConvertFromWin32(WSAGetLastError()));
522#endif /* RT_OS_WINDOWS */
523
524 /*
525 * Write the fixed properties first.
526 */
527 VBoxServiceVMInfoWriteFixedProperties();
528
529 /*
530 * Now enter the loop retrieving runtime data continuously.
531 */
532 for (;;)
533 {
534 rc = VBoxServiceVMInfoWriteUsers();
535 if (RT_FAILURE(rc))
536 break;
537
538 rc = VBoxServiceVMInfoWriteNetwork();
539 if (RT_FAILURE(rc))
540 break;
541
542 /*
543 * Block for a while.
544 *
545 * The event semaphore takes care of ignoring interruptions and it
546 * allows us to implement service wakeup later.
547 */
548 if (*pfShutdown)
549 break;
550 int rc2 = RTSemEventMultiWait(g_hVMInfoEvent, g_cMsVMInfoInterval);
551 if (*pfShutdown)
552 break;
553 if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
554 {
555 VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
556 rc = rc2;
557 break;
558 }
559 }
560
561#ifdef RT_OS_WINDOWS
562 WSACleanup();
563#endif
564
565 return rc;
566}
567
568
569/** @copydoc VBOXSERVICE::pfnStop */
570static DECLCALLBACK(void) VBoxServiceVMInfoStop(void)
571{
572 RTSemEventMultiSignal(g_hVMInfoEvent);
573}
574
575
576/** @copydoc VBOXSERVICE::pfnTerm */
577static DECLCALLBACK(void) VBoxServiceVMInfoTerm(void)
578{
579 int rc;
580
581 if (g_hVMInfoEvent != NIL_RTSEMEVENTMULTI)
582 {
583 /** @todo temporary solution: Zap all values which are not valid
584 * anymore when VM goes down (reboot/shutdown ). Needs to
585 * be replaced with "temporary properties" later.
586 *
587 * One idea is to introduce a (HGCM-)session guest property
588 * flag meaning that a guest property is only valid as long
589 * as the HGCM session isn't closed (e.g. guest application
590 * terminates). [don't remove till implemented]
591 */
592 /** @todo r=bird: Drop the VbglR3GuestPropDelSet call here and use the cache
593 * since it remembers what we've written. */
594 /* Delete the "../Net" branch. */
595 const char *apszPat[1] = { "/VirtualBox/GuestInfo/Net/*" };
596 rc = VbglR3GuestPropDelSet(g_uVMInfoGuestPropSvcClientID, &apszPat[0], RT_ELEMENTS(apszPat));
597
598 /* Destroy property cache. */
599 VBoxServicePropCacheDestroy(&g_VMInfoPropCache);
600
601 /* Disconnect from guest properties service. */
602 rc = VbglR3GuestPropDisconnect(g_uVMInfoGuestPropSvcClientID);
603 if (RT_FAILURE(rc))
604 VBoxServiceError("Failed to disconnect from guest property service! Error: %Rrc\n", rc);
605 g_uVMInfoGuestPropSvcClientID = 0;
606
607 RTSemEventMultiDestroy(g_hVMInfoEvent);
608 g_hVMInfoEvent = NIL_RTSEMEVENTMULTI;
609 }
610}
611
612
613/**
614 * The 'vminfo' service description.
615 */
616VBOXSERVICE g_VMInfo =
617{
618 /* pszName. */
619 "vminfo",
620 /* pszDescription. */
621 "Virtual Machine Information",
622 /* pszUsage. */
623 "[--vminfo-interval <ms>]"
624 ,
625 /* pszOptions. */
626 " --vminfo-interval Specifies the interval at which to retrieve the\n"
627 " VM information. The default is 10000 ms.\n"
628 ,
629 /* methods */
630 VBoxServiceVMInfoPreInit,
631 VBoxServiceVMInfoOption,
632 VBoxServiceVMInfoInit,
633 VBoxServiceVMInfoWorker,
634 VBoxServiceVMInfoStop,
635 VBoxServiceVMInfoTerm
636};
637
Note: See TracBrowser for help on using the repository browser.

© 2024 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette