VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/NetworkServiceRunner.cpp

Last change on this file was 98292, checked in by vboxsync, 16 months ago

Main/src-server: rc -> hrc/vrc. Enabled scm rc checks. bugref:10223

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 9.1 KB
Line 
1/* $Id: NetworkServiceRunner.cpp 98292 2023-01-25 01:14:53Z vboxsync $ */
2/** @file
3 * VirtualBox Main - interface for VBox DHCP server
4 */
5
6/*
7 * Copyright (C) 2009-2023 Oracle and/or its affiliates.
8 *
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
26 */
27
28
29/*********************************************************************************************************************************
30* Header Files *
31*********************************************************************************************************************************/
32#include "NetworkServiceRunner.h"
33
34#include <iprt/env.h>
35#include <iprt/err.h>
36#include <iprt/log.h>
37#include <iprt/process.h>
38#include <iprt/path.h>
39#include <iprt/param.h>
40#include <iprt/thread.h>
41
42
43/*********************************************************************************************************************************
44* Global Variables *
45*********************************************************************************************************************************/
46/*static*/ const char * const NetworkServiceRunner::kpszKeyNetwork = "--network";
47/*static*/ const char * const NetworkServiceRunner::kpszKeyTrunkType = "--trunk-type";
48/*static*/ const char * const NetworkServiceRunner::kpszTrunkName = "--trunk-name";
49/*static*/ const char * const NetworkServiceRunner::kpszMacAddress = "--mac-address";
50/*static*/ const char * const NetworkServiceRunner::kpszIpAddress = "--ip-address";
51/*static*/ const char * const NetworkServiceRunner::kpszIpNetmask = "--netmask";
52/*static*/ const char * const NetworkServiceRunner::kpszKeyNeedMain = "--need-main";
53
54
55/*********************************************************************************************************************************
56* Structures and Typedefs *
57*********************************************************************************************************************************/
58/**
59 * Internal data the rest of the world does not need to be bothered with.
60 *
61 * @note no 'm' prefix here, as the runner is accessing it thru an 'm' member.
62 */
63struct NetworkServiceRunner::Data
64{
65 /** The process filename. */
66 const char *pszProcName;
67 /** Actual size of papszArgs. */
68 size_t cArgs;
69 /** Number of entries allocated for papszArgs. */
70 size_t cArgsAlloc;
71 /** The argument vector.
72 * Each entry is a string allocation via RTStrDup. The zero'th entry is
73 * filled in by start(). */
74 char **papszArgs;
75 /** The process ID. */
76 RTPROCESS Process;
77 /** Whether to kill the process on stopping. */
78 bool fKillProcessOnStop;
79
80 Data(const char* aProcName)
81 : pszProcName(aProcName)
82 , cArgs(0)
83 , cArgsAlloc(0)
84 , papszArgs(NULL)
85 , Process(NIL_RTPROCESS)
86 , fKillProcessOnStop(false)
87 {}
88
89 ~Data()
90 {
91 resetArguments();
92 }
93
94 void resetArguments()
95 {
96 for (size_t i = 0; i < cArgs; i++)
97 RTStrFree(papszArgs[i]);
98 RTMemFree(papszArgs);
99 cArgs = 0;
100 cArgsAlloc = 0;
101 papszArgs = NULL;
102 }
103};
104
105
106
107NetworkServiceRunner::NetworkServiceRunner(const char *aProcName)
108{
109 m = new NetworkServiceRunner::Data(aProcName);
110}
111
112
113NetworkServiceRunner::~NetworkServiceRunner()
114{
115 stop();
116 delete m;
117 m = NULL;
118}
119
120
121/**
122 * Adds one argument to the server command line.
123 *
124 * @returns IPRT status code.
125 * @param pszArgument The argument to add.
126 */
127int NetworkServiceRunner::addArgument(const char *pszArgument)
128{
129 AssertPtr(pszArgument);
130
131 /*
132 * Grow the argument vector as needed.
133 * Make sure unused space is NULL'ed and that we've got an extra entry for
134 * the NULL terminator. Arguments starts at 1 of course, 0 being the executable.
135 */
136 size_t const i = RT_MAX(m->cArgs, 1);
137 size_t const cAlloc = m->cArgsAlloc;
138 if (i + 1 /*NULL terminator*/ >= m->cArgsAlloc)
139 {
140 size_t cNewAlloc = cAlloc ? cAlloc : 2;
141 do
142 cNewAlloc *= 2;
143 while (cNewAlloc <= i + 1);
144 void *pvNew = RTMemRealloc(m->papszArgs, cNewAlloc * sizeof(m->papszArgs[0]));
145 AssertReturn(pvNew, VERR_NO_MEMORY);
146 m->papszArgs = (char **)pvNew;
147 RT_BZERO(&m->papszArgs[m->cArgsAlloc], (cNewAlloc - cAlloc) * sizeof(m->papszArgs[0]));
148 m->cArgsAlloc = cNewAlloc;
149 }
150
151 /*
152 * Add it.
153 */
154 m->papszArgs[i] = RTStrDup(pszArgument);
155 if (m->papszArgs[i])
156 {
157 m->cArgs = i + 1;
158 Assert(m->papszArgs[m->cArgs] == NULL);
159 return VINF_SUCCESS;
160 }
161 return VERR_NO_STR_MEMORY;
162}
163
164
165/**
166 * Adds a pair of arguments, e.g. option + value.
167 *
168 * @returns IPRT status code.
169 */
170int NetworkServiceRunner::addArgPair(const char *pszOption, const char *pszValue)
171{
172 int vrc = addArgument(pszOption);
173 if (RT_SUCCESS(vrc))
174 vrc = addArgument(pszValue);
175 return vrc;
176}
177
178
179void NetworkServiceRunner::resetArguments()
180{
181 m->resetArguments();
182}
183
184
185void NetworkServiceRunner::detachFromServer()
186{
187 m->Process = NIL_RTPROCESS;
188}
189
190
191int NetworkServiceRunner::start(bool aKillProcessOnStop)
192{
193 if (isRunning())
194 return VINF_ALREADY_INITIALIZED;
195
196 /*
197 * Construct the path to the executable and put in into the argument vector.
198 * ASSUME it is relative to the directory that holds VBoxSVC.
199 */
200 char szExePath[RTPATH_MAX];
201 AssertReturn(RTProcGetExecutablePath(szExePath, RTPATH_MAX), VERR_FILENAME_TOO_LONG);
202 RTPathStripFilename(szExePath);
203 int vrc = RTPathAppend(szExePath, sizeof(szExePath), m->pszProcName);
204 AssertLogRelRCReturn(vrc, vrc);
205
206 if (m->cArgs == 0 && m->cArgsAlloc == 0)
207 {
208 m->cArgsAlloc = 2;
209 m->papszArgs = (char **)RTMemAllocZ(sizeof(m->papszArgs[0]) * 2);
210 AssertReturn(m->papszArgs, VERR_NO_MEMORY);
211 }
212 else
213 Assert(m->cArgsAlloc >= 2);
214 RTStrFree(m->papszArgs[0]);
215 m->papszArgs[0] = RTStrDup(szExePath);
216 AssertReturn(m->papszArgs[0], VERR_NO_MEMORY);
217 if (m->cArgs == 0)
218 m->cArgs = 1;
219
220 /*
221 * Start the process:
222 */
223 vrc = RTProcCreate(szExePath, m->papszArgs, RTENV_DEFAULT, 0, &m->Process);
224 if (RT_SUCCESS(vrc))
225 LogRel(("NetworkServiceRunning: started '%s', pid %RTproc\n", m->pszProcName, m->Process));
226 else
227 m->Process = NIL_RTPROCESS;
228
229 m->fKillProcessOnStop = aKillProcessOnStop;
230
231 return vrc;
232}
233
234
235int NetworkServiceRunner::stop()
236{
237 /*
238 * If the process already terminated, this function will also grab the exit
239 * status and transition the process out of zombie status.
240 */
241 if (!isRunning())
242 return VINF_OBJECT_DESTROYED;
243
244 bool fDoKillProc = true;
245
246 if (!m->fKillProcessOnStop)
247 {
248 /*
249 * This is a VBoxSVC Main client. Do NOT kill it but assume it was shut
250 * down politely. Wait up to 1 second until the process is killed before
251 * doing the final hard kill.
252 */
253 for (unsigned int i = 0; i < 100; i++)
254 {
255 if (!isRunning())
256 {
257 fDoKillProc = false;
258 break;
259 }
260 RTThreadSleep(10);
261 }
262 }
263
264 if (fDoKillProc)
265 {
266 LogRel(("NetworkServiceRunning: killing %s, pid %RTproc...\n", m->pszProcName, m->Process));
267 RTProcTerminate(m->Process);
268
269 int vrc = RTProcWait(m->Process, RTPROCWAIT_FLAGS_BLOCK, NULL);
270 NOREF(vrc);
271 }
272
273 m->Process = NIL_RTPROCESS;
274 return VINF_SUCCESS;
275}
276
277
278/**
279 * Checks if the service process is still running.
280 *
281 * @returns true if running, false if not.
282 */
283bool NetworkServiceRunner::isRunning()
284{
285 RTPROCESS Process = m->Process;
286 if (Process != NIL_RTPROCESS)
287 {
288 RTPROCSTATUS ExitStatus;
289 int vrc = RTProcWait(Process, RTPROCWAIT_FLAGS_NOBLOCK, &ExitStatus);
290 if (vrc == VERR_PROCESS_RUNNING)
291 return true;
292 LogRel(("NetworkServiceRunning: %s (pid %RTproc) stopped: iStatus=%u enmReason=%d\n",
293 m->pszProcName, m->Process, ExitStatus.iStatus, ExitStatus.enmReason));
294 m->Process = NIL_RTPROCESS;
295 }
296 return false;
297}
298
299
300/**
301 * Gets the process ID of a running service, NIL_PROCESS if not running.
302 */
303RTPROCESS NetworkServiceRunner::getPid() const
304{
305 return m->Process;
306}
307
Note: See TracBrowser for help on using the repository browser.

© 2023 Oracle
ContactPrivacy policyTerms of Use