VirtualBox

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

Last change on this file since 94173 was 93115, checked in by vboxsync, 3 years ago

scm --update-copyright-year

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