VirtualBox

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

Last change on this file since 79761 was 79761, checked in by vboxsync, 5 years ago

Main/DHCPServer,Dhcpd,VBoxManage: Added --log option to the DHCP server so we can start logging early. Added log rotation and limits. Put the config file next to the log and leases file. Validate DHCP options by reusing the parser code from the server, adding a bunch more DHCP options to the parser. Removed legacy and hardcoded configuration options from the dhcp server, it's all config file now. Fixed a bug in the option parsing of the VBoxManage dhcpserver add/modify commands. bugref:9288

  • 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 79761 2019-07-14 03:18:41Z vboxsync $ */
2/** @file
3 * VirtualBox Main - interface for VBox DHCP server
4 */
5
6/*
7 * Copyright (C) 2009-2019 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