VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/win/svcmain.cpp@ 57130

Last change on this file since 57130 was 55980, checked in by vboxsync, 10 years ago

iprt/log.h,++: Added extended logger instance getters that also checks whether the given logger and group-flags are enabled, making the LogRel* checks more efficient in avoid uncessary RTLogLoggerEx parameter building and calls. Ditto for debug logging. The LOG_INSTANCE and LOG_REL_INSTANCE tricks are gone for now.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 13.7 KB
Line 
1/* $Id: svcmain.cpp 55980 2015-05-20 17:35:22Z vboxsync $ */
2/** @file
3 *
4 * SVCMAIN - COM out-of-proc server main entry
5 */
6
7/*
8 * Copyright (C) 2004-2013 Oracle Corporation
9 *
10 * This file is part of VirtualBox Open Source Edition (OSE), as
11 * available from http://www.virtualbox.org. This file is free software;
12 * you can redistribute it and/or modify it under the terms of the GNU
13 * General Public License (GPL) as published by the Free Software
14 * Foundation, in version 2 as it comes in the "COPYING" file of the
15 * VirtualBox OSE distribution. VirtualBox OSE is distributed in the
16 * hope that it will be useful, but WITHOUT ANY WARRANTY of any kind.
17 */
18
19#include <Windows.h>
20#include <stdio.h>
21#include <stdlib.h>
22
23#include "VBox/com/defs.h"
24
25#include "VBox/com/com.h"
26
27#include "VBox/com/VirtualBox.h"
28
29#include "VirtualBoxImpl.h"
30#include "Logging.h"
31
32#include "svchlp.h"
33
34#include <VBox/err.h>
35#include <iprt/buildconfig.h>
36#include <iprt/initterm.h>
37#include <iprt/string.h>
38#include <iprt/uni.h>
39#include <iprt/path.h>
40#include <iprt/getopt.h>
41#include <iprt/message.h>
42
43#include <atlbase.h>
44#include <atlcom.h>
45
46#define _ATL_FREE_THREADED
47
48class CExeModule : public CComModule
49{
50public:
51 LONG Unlock();
52 DWORD dwThreadID;
53 HANDLE hEventShutdown;
54 void MonitorShutdown();
55 bool StartMonitor();
56 bool bActivity;
57};
58
59const DWORD dwTimeOut = 5000; /* time for EXE to be idle before shutting down */
60const DWORD dwPause = 100; /* time to wait for threads to finish up */
61
62/* Passed to CreateThread to monitor the shutdown event */
63static DWORD WINAPI MonitorProc(void* pv)
64{
65 CExeModule* p = (CExeModule*)pv;
66 p->MonitorShutdown();
67 return 0;
68}
69
70LONG CExeModule::Unlock()
71{
72 LONG l = CComModule::Unlock();
73 if (l == 0)
74 {
75 bActivity = true;
76 SetEvent(hEventShutdown); /* tell monitor that we transitioned to zero */
77 }
78 return l;
79}
80
81/* Monitors the shutdown event */
82void CExeModule::MonitorShutdown()
83{
84 while (1)
85 {
86 WaitForSingleObject(hEventShutdown, INFINITE);
87 DWORD dwWait=0;
88 do
89 {
90 bActivity = false;
91 dwWait = WaitForSingleObject(hEventShutdown, dwTimeOut);
92 } while (dwWait == WAIT_OBJECT_0);
93 /* timed out */
94 if (!bActivity && m_nLockCnt == 0) /* if no activity let's really bail */
95 {
96 /* Disable log rotation at this point, worst case a log file
97 * becomes slightly bigger than it should. Avoids quirks with
98 * log rotation: there might be another API service process
99 * running at this point which would rotate the logs concurrently,
100 * creating a mess. */
101 PRTLOGGER pReleaseLogger = RTLogRelGetDefaultInstance();
102 if (pReleaseLogger)
103 {
104 char szDest[1024];
105 int rc = RTLogGetDestinations(pReleaseLogger, szDest, sizeof(szDest));
106 if (RT_SUCCESS(rc))
107 {
108 rc = RTStrCat(szDest, sizeof(szDest), " nohistory");
109 if (RT_SUCCESS(rc))
110 {
111 rc = RTLogDestinations(pReleaseLogger, szDest);
112 AssertRC(rc);
113 }
114 }
115 }
116#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
117 CoSuspendClassObjects();
118 if (!bActivity && m_nLockCnt == 0)
119#endif
120 break;
121 }
122 }
123 CloseHandle(hEventShutdown);
124 PostThreadMessage(dwThreadID, WM_QUIT, 0, 0);
125}
126
127bool CExeModule::StartMonitor()
128{
129 hEventShutdown = CreateEvent(NULL, false, false, NULL);
130 if (hEventShutdown == NULL)
131 return false;
132 DWORD dwThreadID;
133 HANDLE h = CreateThread(NULL, 0, MonitorProc, this, 0, &dwThreadID);
134 return (h != NULL);
135}
136
137CExeModule _Module;
138
139BEGIN_OBJECT_MAP(ObjectMap)
140 OBJECT_ENTRY(CLSID_VirtualBox, VirtualBox)
141END_OBJECT_MAP()
142
143
144/////////////////////////////////////////////////////////////////////////////
145//
146int WINAPI WinMain(HINSTANCE hInstance, HINSTANCE /*hPrevInstance*/, LPSTR /*lpCmdLine*/, int /*nShowCmd*/)
147{
148 int argc = __argc;
149 char **argv = __argv;
150
151 /*
152 * Need to parse the command line before initializing the VBox runtime so we can
153 * change to the user home directory before logs are being created.
154 */
155 for (int i = 1; i < argc; i++)
156 if ( (argv[i][0] == '/' || argv[i][0] == '-')
157 && stricmp(&argv[i][1], "embedding") == 0) /* ANSI */
158 {
159 /* %HOMEDRIVE%%HOMEPATH% */
160 wchar_t wszHome[RTPATH_MAX];
161 DWORD cEnv = GetEnvironmentVariable(L"HOMEDRIVE", &wszHome[0], RTPATH_MAX);
162 if (cEnv && cEnv < RTPATH_MAX)
163 {
164 DWORD cwc = cEnv; /* doesn't include NUL */
165 cEnv = GetEnvironmentVariable(L"HOMEPATH", &wszHome[cEnv], RTPATH_MAX - cwc);
166 if (cEnv && cEnv < RTPATH_MAX - cwc)
167 {
168 /* If this fails there is nothing we can do. Ignore. */
169 SetCurrentDirectory(wszHome);
170 }
171 }
172 }
173
174 /*
175 * Initialize the VBox runtime without loading
176 * the support driver.
177 */
178 RTR3InitExe(argc, &argv, 0);
179
180 /* Note that all options are given lowercase/camel case/uppercase to
181 * approximate case insensitive matching, which RTGetOpt doesn't offer. */
182 static const RTGETOPTDEF s_aOptions[] =
183 {
184 { "--embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
185 { "-embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
186 { "/embedding", 'e', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
187 { "--unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
188 { "-unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
189 { "/unregserver", 'u', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
190 { "--regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
191 { "-regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
192 { "/regserver", 'r', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
193 { "--reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
194 { "-reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
195 { "/reregserver", 'f', RTGETOPT_REQ_NOTHING | RTGETOPT_FLAG_ICASE },
196 { "--helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
197 { "-helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
198 { "/helper", 'H', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
199 { "--logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
200 { "-logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
201 { "/logfile", 'F', RTGETOPT_REQ_STRING | RTGETOPT_FLAG_ICASE },
202 { "--logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
203 { "-logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
204 { "/logrotate", 'R', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
205 { "--logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
206 { "-logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
207 { "/logsize", 'S', RTGETOPT_REQ_UINT64 | RTGETOPT_FLAG_ICASE },
208 { "--loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
209 { "-loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
210 { "/loginterval", 'I', RTGETOPT_REQ_UINT32 | RTGETOPT_FLAG_ICASE },
211 };
212
213 bool fRun = true;
214 bool fRegister = false;
215 bool fUnregister = false;
216 const char *pszPipeName = NULL;
217 const char *pszLogFile = NULL;
218 uint32_t cHistory = 10; // enable log rotation, 10 files
219 uint32_t uHistoryFileTime = RT_SEC_1DAY; // max 1 day per file
220 uint64_t uHistoryFileSize = 100 * _1M; // max 100MB per file
221
222 RTGETOPTSTATE GetOptState;
223 int vrc = RTGetOptInit(&GetOptState, argc, argv, &s_aOptions[0], RT_ELEMENTS(s_aOptions), 1, 0 /*fFlags*/);
224 AssertRC(vrc);
225
226 RTGETOPTUNION ValueUnion;
227 while ((vrc = RTGetOpt(&GetOptState, &ValueUnion)))
228 {
229 switch (vrc)
230 {
231 case 'e':
232 /* already handled above */
233 break;
234
235 case 'u':
236 fUnregister = true;
237 fRun = false;
238 break;
239
240 case 'r':
241 fRegister = true;
242 fRun = false;
243 break;
244
245 case 'f':
246 fUnregister = true;
247 fRegister = true;
248 fRun = false;
249 break;
250
251 case 'H':
252 pszPipeName = ValueUnion.psz;
253 if (!pszPipeName)
254 pszPipeName = "";
255 fRun = false;
256 break;
257
258 case 'F':
259 pszLogFile = ValueUnion.psz;
260 break;
261
262 case 'R':
263 cHistory = ValueUnion.u32;
264 break;
265
266 case 'S':
267 uHistoryFileSize = ValueUnion.u64;
268 break;
269
270 case 'I':
271 uHistoryFileTime = ValueUnion.u32;
272 break;
273
274 case 'h':
275 {
276 TCHAR txt[]= L"Options:\n\n"
277 L"/RegServer:\tregister COM out-of-proc server\n"
278 L"/UnregServer:\tunregister COM out-of-proc server\n"
279 L"/ReregServer:\tunregister and register COM server\n"
280 L"no options:\trun the server";
281 TCHAR title[]=_T("Usage");
282 fRun = false;
283 MessageBox(NULL, txt, title, MB_OK);
284 return 0;
285 }
286
287 case 'V':
288 {
289 char *psz = NULL;
290 RTStrAPrintf(&psz, "%sr%s\n", RTBldCfgVersion(), RTBldCfgRevisionStr());
291 PRTUTF16 txt = NULL;
292 RTStrToUtf16(psz, &txt);
293 TCHAR title[]=_T("Version");
294 fRun = false;
295 MessageBox(NULL, txt, title, MB_OK);
296 RTStrFree(psz);
297 RTUtf16Free(txt);
298 return 0;
299 }
300
301 default:
302 /** @todo this assumes that stderr is visible, which is not
303 * true for standard Windows applications. */
304 /* continue on command line errors... */
305 RTGetOptPrintError(vrc, &ValueUnion);
306 }
307 }
308
309 /* Only create the log file when running VBoxSVC normally, but not when
310 * registering/unregistering or calling the helper functionality. */
311 if (fRun)
312 {
313 /** @todo Merge this code with server.cpp (use Logging.cpp?). */
314 char szLogFile[RTPATH_MAX];
315 if (!pszLogFile)
316 {
317 vrc = com::GetVBoxUserHomeDirectory(szLogFile, sizeof(szLogFile));
318 if (RT_SUCCESS(vrc))
319 vrc = RTPathAppend(szLogFile, sizeof(szLogFile), "VBoxSVC.log");
320 }
321 else
322 {
323 if (!RTStrPrintf(szLogFile, sizeof(szLogFile), "%s", pszLogFile))
324 vrc = VERR_NO_MEMORY;
325 }
326 if (RT_FAILURE(vrc))
327 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to create logging file name, rc=%Rrc", vrc);
328
329 char szError[RTPATH_MAX + 128];
330 vrc = com::VBoxLogRelCreate("COM Server", szLogFile,
331 RTLOGFLAGS_PREFIX_THREAD | RTLOGFLAGS_PREFIX_TIME_PROG,
332 VBOXSVC_LOG_DEFAULT, "VBOXSVC_RELEASE_LOG",
333 RTLOGDEST_FILE, UINT32_MAX /* cMaxEntriesPerGroup */,
334 cHistory, uHistoryFileTime, uHistoryFileSize,
335 szError, sizeof(szError));
336 if (RT_FAILURE(vrc))
337 return RTMsgErrorExit(RTEXITCODE_FAILURE, "failed to open release log (%s, %Rrc)", szError, vrc);
338 }
339
340 int nRet = 0;
341 HRESULT hRes = com::Initialize();
342
343 _ASSERTE(SUCCEEDED(hRes));
344 _Module.Init(ObjectMap, hInstance, &LIBID_VirtualBox);
345 _Module.dwThreadID = GetCurrentThreadId();
346
347 if (!fRun)
348 {
349 if (fUnregister)
350 {
351 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, FALSE);
352 nRet = _Module.UnregisterServer(TRUE);
353 }
354 if (fRegister)
355 {
356 _Module.UpdateRegistryFromResource(IDR_VIRTUALBOX, TRUE);
357 nRet = _Module.RegisterServer(TRUE);
358 }
359 if (pszPipeName)
360 {
361 Log(("SVCMAIN: Processing Helper request (cmdline=\"%s\")...\n", pszPipeName));
362
363 if (!*pszPipeName)
364 vrc = VERR_INVALID_PARAMETER;
365
366 if (RT_SUCCESS(vrc))
367 {
368 /* do the helper job */
369 SVCHlpServer server;
370 vrc = server.open(pszPipeName);
371 if (RT_SUCCESS(vrc))
372 vrc = server.run();
373 }
374 if (RT_FAILURE(vrc))
375 {
376 Log(("SVCMAIN: Failed to process Helper request (%Rrc).", vrc));
377 nRet = 1;
378 }
379 }
380 }
381 else
382 {
383 _Module.StartMonitor();
384#if _WIN32_WINNT >= 0x0400 & defined(_ATL_FREE_THREADED)
385 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE | REGCLS_SUSPENDED);
386 _ASSERTE(SUCCEEDED(hRes));
387 hRes = CoResumeClassObjects();
388#else
389 hRes = _Module.RegisterClassObjects(CLSCTX_LOCAL_SERVER, REGCLS_MULTIPLEUSE);
390#endif
391 _ASSERTE(SUCCEEDED(hRes));
392
393 MSG msg;
394 while (GetMessage(&msg, 0, 0, 0))
395 DispatchMessage(&msg);
396
397 _Module.RevokeClassObjects();
398 Sleep(dwPause); //wait for any threads to finish
399 }
400
401 _Module.Term();
402
403 com::Shutdown();
404
405 Log(("SVCMAIN: Returning, COM server process ends.\n"));
406 return nRet;
407}
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