VirtualBox

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

Last change on this file since 19503 was 19374, checked in by vboxsync, 16 years ago

VBoxService/common: SVN props.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.8 KB
Line 
1/* $Id: VBoxServiceVMInfo.cpp 19374 2009-05-05 13:23:32Z vboxsync $ */
2/** @file
3 * VBoxVMInfo - Virtual machine (guest) information for the host.
4 */
5
6/*
7 * Copyright (C) 2009 Sun Microsystems, Inc.
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 * Please contact Sun Microsystems, Inc., 4150 Network Circle, Santa
18 * Clara, CA 95054 USA or visit http://www.sun.com if you need
19 * additional information or have any questions.
20 */
21
22
23
24/*******************************************************************************
25* Header Files *
26*******************************************************************************/
27#ifdef RT_OS_WINDOWS
28#include <winsock2.h>
29#include <ws2tcpip.h>
30#include <windows.h>
31#include <Ntsecapi.h>
32#else
33# include <unistd.h>
34# include <errno.h>
35#endif
36
37#include <iprt/mem.h>
38#include <iprt/thread.h>
39#include <iprt/string.h>
40#include <iprt/semaphore.h>
41#include <iprt/system.h>
42#include <iprt/time.h>
43#include <iprt/assert.h>
44#include <VBox/VBoxGuest.h>
45#include "VBoxServiceInternal.h"
46#include "VBoxServiceUtils.h"
47
48
49/*******************************************************************************
50* Global Variables *
51*******************************************************************************/
52/** The vminfo interval (millseconds). */
53uint32_t g_VMInfoInterval = 0;
54/** The semaphore we're blocking on. */
55static RTSEMEVENTMULTI g_VMInfoEvent = NIL_RTSEMEVENTMULTI;
56/** The guest property service client ID. */
57static uint32_t g_VMInfoGuestPropSvcClientID = 0;
58/** Number of logged in users in OS. */
59static uint32_t g_VMInfoLoggedInUsers = 0;
60#ifdef RT_OS_WINDOWS
61/** Function prototypes for dynamic loading. */
62fnWTSGetActiveConsoleSessionId g_pfnWTSGetActiveConsoleSessionId = NULL;
63/** External functions. */
64extern int VboxServiceWinGetAddsVersion(uint32_t uiClientID);
65extern int VboxServiceWinGetComponentVersions(uint32_t uiClientID);
66#endif
67
68
69/** @copydoc VBOXSERVICE::pfnPreInit */
70static DECLCALLBACK(int) VBoxServiceVMInfoPreInit(void)
71{
72 return VINF_SUCCESS;
73}
74
75
76/** @copydoc VBOXSERVICE::pfnOption */
77static DECLCALLBACK(int) VBoxServiceVMInfoOption(const char **ppszShort, int argc, char **argv, int *pi)
78{
79 int rc = -1;
80 if (ppszShort)
81 /* no short options */;
82 else if (!strcmp(argv[*pi], "--vminfo-interval"))
83 rc = VBoxServiceArgUInt32(argc, argv, "", pi,
84 &g_VMInfoInterval, 1, UINT32_MAX - 1);
85 return rc;
86}
87
88
89/** @copydoc VBOXSERVICE::pfnInit */
90static DECLCALLBACK(int) VBoxServiceVMInfoInit(void)
91{
92 /*
93 * If not specified, find the right interval default.
94 * Then create the event sem to block on.
95 */
96 if (!g_VMInfoInterval)
97 g_VMInfoInterval = g_DefaultInterval * 1000;
98 if (!g_VMInfoInterval)
99 g_VMInfoInterval = 10 * 1000;
100
101 int rc = RTSemEventMultiCreate(&g_VMInfoEvent);
102 AssertRC(rc);
103
104#ifdef RT_OS_WINDOWS
105 /* Get function pointers. */
106 HMODULE hKernel32 = LoadLibrary(_T("kernel32"));
107 if (NULL != hKernel32)
108 {
109 g_pfnWTSGetActiveConsoleSessionId = (fnWTSGetActiveConsoleSessionId)GetProcAddress(hKernel32, "WTSGetActiveConsoleSessionId");
110 FreeLibrary(hKernel32);
111 }
112#endif
113
114 rc = VbglR3GuestPropConnect(&g_VMInfoGuestPropSvcClientID);
115 if (!RT_SUCCESS(rc))
116 {
117 VBoxServiceError("Failed to connect to the guest property service! Error: %Rrc\n", rc);
118 }
119 else
120 {
121 VBoxServiceVerbose(3, "Property Service Client ID: %ld\n", g_VMInfoGuestPropSvcClientID);
122 }
123
124 return rc;
125}
126
127
128/** @copydoc VBOXSERVICE::pfnWorker */
129DECLCALLBACK(int) VBoxServiceVMInfoWorker(bool volatile *pfShutdown)
130{
131 int rc = VINF_SUCCESS;
132
133 /*
134 * Tell the control thread that it can continue
135 * spawning services.
136 */
137 RTThreadUserSignal(RTThreadSelf());
138
139#ifdef RT_OS_WINDOWS
140 /* Required for network information (must be called per thread). */
141 WSADATA wsaData;
142 if (WSAStartup(MAKEWORD(2, 2), &wsaData)) {
143 VBoxServiceError("WSAStartup failed! Error: %Rrc\n", RTErrConvertFromWin32(WSAGetLastError()));
144 }
145#endif /* !RT_OS_WINDOWS */
146
147 /* First get information that won't change while the OS is running. */
148 char szInfo[256] = {0};
149 rc = RTSystemQueryOSInfo(RTSYSOSINFO_PRODUCT, szInfo, sizeof(szInfo));
150 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/Product", szInfo);
151
152 rc = RTSystemQueryOSInfo(RTSYSOSINFO_RELEASE, szInfo, sizeof(szInfo));
153 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/Release", szInfo);
154
155 rc = RTSystemQueryOSInfo(RTSYSOSINFO_VERSION, szInfo, sizeof(szInfo));
156 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/Version", szInfo);
157
158 rc = RTSystemQueryOSInfo(RTSYSOSINFO_SERVICE_PACK, szInfo, sizeof(szInfo));
159 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/ServicePack", szInfo);
160
161 /* Retrieve version information about Guest Additions and installed files (components). */
162#ifdef RT_OS_WINDOWS
163 rc = VboxServiceWinGetAddsVersion(g_VMInfoGuestPropSvcClientID);
164 rc = VboxServiceWinGetComponentVersions(g_VMInfoGuestPropSvcClientID);
165#else
166 /** @todo */
167#endif
168
169 /* Now enter the loop retrieving runtime data continuously. */
170 unsigned cErrors = 0;
171 for (;;)
172 {
173 /* Enumerate logged in users. */
174 uint32_t uiUserCount = 0;
175 char szUserList[4096] = {0};
176
177#ifdef RT_OS_WINDOWS
178 PLUID pSessions = NULL;
179 ULONG ulCount = 0;
180 NTSTATUS r = 0;
181
182 char* pszTemp = NULL;
183
184 /* This function can report stale or orphaned interactive logon sessions of already logged
185 off users (especially in Windows 2000). */
186 r = ::LsaEnumerateLogonSessions(&ulCount, &pSessions);
187 VBoxServiceVerbose(3, "Users: Found %ld users.\n", ulCount);
188
189 if (r != STATUS_SUCCESS)
190 {
191 VBoxServiceError("LsaEnumerate failed %lu\n", LsaNtStatusToWinError(r));
192 return 1;
193 }
194
195 PLUID pLuid = NULL;
196 DWORD dwNumOfProcLUIDs = VboxServiceVMInfoWinGetLUIDsFromProcesses(&pLuid);
197
198 VBOXSERVICEVMINFOUSER userInfo;
199 ZeroMemory (&userInfo, sizeof(VBOXSERVICEVMINFOUSER));
200
201 for (int i = 0; i<(int)ulCount; i++)
202 {
203 if (VboxServiceVMInfoWinIsLoggedIn(&userInfo, &pSessions[i], pLuid, dwNumOfProcLUIDs))
204 {
205 if (uiUserCount > 0)
206 strcat (szUserList, ",");
207
208 uiUserCount++;
209
210 RTUtf16ToUtf8(userInfo.szUser, &pszTemp);
211 strcat(szUserList, pszTemp);
212 RTMemFree(pszTemp);
213 }
214 }
215
216 if (NULL != pLuid)
217 ::LocalFree (pLuid);
218
219 ::LsaFreeReturnBuffer(pSessions);
220#else
221 /** @todo Nothing here yet - Implement other platforms here. */
222#endif /* !RT_OS_WINDOWS */
223
224 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/LoggedInUsersList", (uiUserCount > 0) ? szUserList : NULL);
225 VboxServiceWritePropInt(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/LoggedInUsers", uiUserCount);
226 if (g_VMInfoLoggedInUsers != uiUserCount || g_VMInfoLoggedInUsers == INT32_MAX)
227 {
228 /* Update this property ONLY if there is a real change from no users to
229 * users or vice versa. The only exception is that the initialization
230 * of a_pCtx->cUsers forces an update, but only once. This ensures
231 * consistent property settings even if the VM aborted previously. */
232 if (uiUserCount == 0)
233 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/NoLoggedInUsers", "true");
234 else if (g_VMInfoLoggedInUsers == 0 || uiUserCount == INT32_MAX)
235 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/NoLoggedInUsers", "false");
236 }
237 g_VMInfoLoggedInUsers = uiUserCount;
238
239 /* Get network configuration. */
240 /** @todo Throw this code into a separate function/module? */
241#ifdef RT_OS_WINDOWS
242 SOCKET sd = WSASocket(AF_INET, SOCK_DGRAM, 0, 0, 0, 0);
243 if (sd == SOCKET_ERROR)
244 {
245 VBoxServiceError("Failed to get a socket: Error %d\n", WSAGetLastError());
246 return -1;
247 }
248
249 INTERFACE_INFO InterfaceList[20] = {0};
250 unsigned long nBytesReturned = 0;
251 if (WSAIoctl(sd,
252 SIO_GET_INTERFACE_LIST,
253 0,
254 0,
255 &InterfaceList,
256 sizeof(InterfaceList),
257 &nBytesReturned,
258 0,
259 0) == SOCKET_ERROR)
260 {
261 VBoxServiceError("Failed calling WSAIoctl: Error: %d\n", WSAGetLastError());
262 return -1;
263 }
264
265 char szPropPath [_MAX_PATH] = {0};
266 char szTemp [_MAX_PATH] = {0};
267 int nNumInterfaces = nBytesReturned / sizeof(INTERFACE_INFO);
268 int iCurIface = 0;
269
270 RTStrPrintf(szPropPath, sizeof(szPropPath), "GuestInfo/Net/Count");
271 VboxServiceWritePropInt(g_VMInfoGuestPropSvcClientID, szPropPath, (nNumInterfaces > 1 ? nNumInterfaces-1 : 0));
272
273 /** @todo Use GetAdaptersInfo() and GetAdapterAddresses (IPv4 + IPv6) for more information. */
274
275 for (int i = 0; i < nNumInterfaces; ++i)
276 {
277 if (InterfaceList[i].iiFlags & IFF_LOOPBACK) /* Skip loopback device. */
278 continue;
279
280 sockaddr_in *pAddress;
281 pAddress = (sockaddr_in *) & (InterfaceList[i].iiAddress);
282 RTStrPrintf(szPropPath, sizeof(szPropPath), "GuestInfo/Net/%d/V4/IP", iCurIface);
283 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, szPropPath, inet_ntoa(pAddress->sin_addr));
284
285 pAddress = (sockaddr_in *) & (InterfaceList[i].iiBroadcastAddress);
286 RTStrPrintf(szPropPath, sizeof(szPropPath), "GuestInfo/Net/%d/V4/Broadcast", iCurIface);
287 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, szPropPath, inet_ntoa(pAddress->sin_addr));
288
289 pAddress = (sockaddr_in *) & (InterfaceList[i].iiNetmask);
290 RTStrPrintf(szPropPath, sizeof(szPropPath), "GuestInfo/Net/%d/V4/Netmask", iCurIface);
291 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, szPropPath, inet_ntoa(pAddress->sin_addr));
292
293 u_long nFlags = InterfaceList[i].iiFlags;
294 if (nFlags & IFF_UP)
295 RTStrPrintf(szTemp, sizeof(szTemp), "Up");
296 else
297 RTStrPrintf(szTemp, sizeof(szTemp), "Down");
298
299 RTStrPrintf(szPropPath, sizeof(szPropPath), "GuestInfo/Net/%d/Status", iCurIface);
300 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, szPropPath, szTemp);
301
302 iCurIface++;
303 }
304
305 closesocket(sd);
306#endif /* !RT_OS_WINDOWS */
307
308 /*
309 * Block for a while.
310 *
311 * The event semaphore takes care of ignoring interruptions and it
312 * allows us to implement service wakeup later.
313 */
314 if (*pfShutdown)
315 break;
316 int rc2 = RTSemEventMultiWait(g_VMInfoEvent, g_VMInfoInterval);
317 if (*pfShutdown)
318 break;
319 if (rc2 != VERR_TIMEOUT && RT_FAILURE(rc2))
320 {
321 VBoxServiceError("RTSemEventMultiWait failed; rc2=%Rrc\n", rc2);
322 rc = rc2;
323 break;
324 }
325 }
326
327#ifdef RT_OS_WINDOWS
328 WSACleanup();
329#endif /* !RT_OS_WINDOWS */
330
331 RTSemEventMultiDestroy(g_VMInfoEvent);
332 g_VMInfoEvent = NIL_RTSEMEVENTMULTI;
333 return rc;
334}
335
336
337/** @copydoc VBOXSERVICE::pfnStop */
338static DECLCALLBACK(void) VBoxServiceVMInfoStop(void)
339{
340 RTSemEventMultiSignal(g_VMInfoEvent);
341}
342
343
344/** @copydoc VBOXSERVICE::pfnTerm */
345static DECLCALLBACK(void) VBoxServiceVMInfoTerm(void)
346{
347 int rc;
348
349 /** @todo temporary solution: Zap all values which are not valid
350 * anymore when VM goes down (reboot/shutdown ). Needs to
351 * be replaced with "temporary properties" later. */
352 rc = VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/LoggedInUsersList", NULL);
353 rc = VboxServiceWritePropInt(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/LoggedInUsers", 0);
354 if (g_VMInfoLoggedInUsers > 0)
355 VboxServiceWriteProp(g_VMInfoGuestPropSvcClientID, "GuestInfo/OS/NoLoggedInUsers", "true");
356
357 const char *apszPat[1] = { "/VirtualBox/GuestInfo/Net/*" };
358 rc = VbglR3GuestPropDelSet(g_VMInfoGuestPropSvcClientID, &apszPat[0], RT_ELEMENTS(apszPat));
359 rc = VboxServiceWritePropInt(g_VMInfoGuestPropSvcClientID, "GuestInfo/Net/Count", 0);
360
361 /* Disconnect from guest properties service. */
362 rc = VbglR3GuestPropDisconnect(g_VMInfoGuestPropSvcClientID);
363 if (RT_FAILURE(rc))
364 VBoxServiceError("Failed to disconnect from guest property service! Error: %Rrc\n", rc);
365
366 if (g_VMInfoEvent != NIL_RTSEMEVENTMULTI)
367 {
368 RTSemEventMultiDestroy(g_VMInfoEvent);
369 g_VMInfoEvent = NIL_RTSEMEVENTMULTI;
370 }
371}
372
373
374/**
375 * The 'vminfo' service description.
376 */
377VBOXSERVICE g_VMInfo =
378{
379 /* pszName. */
380 "vminfo",
381 /* pszDescription. */
382 "Virtual Machine Information",
383 /* pszUsage. */
384 "[--vminfo-interval <ms>]"
385 ,
386 /* pszOptions. */
387 " --vminfo-interval Specifies the interval at which to retrieve the\n"
388 " VM information. The default is 10000 ms.\n"
389 ,
390 /* methods */
391 VBoxServiceVMInfoPreInit,
392 VBoxServiceVMInfoOption,
393 VBoxServiceVMInfoInit,
394 VBoxServiceVMInfoWorker,
395 VBoxServiceVMInfoStop,
396 VBoxServiceVMInfoTerm
397};
398
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