VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostDnsService.cpp@ 89718

Last change on this file since 89718 was 87578, checked in by vboxsync, 4 years ago

Main: Doxygen v1.8.20 seems to get confused by appendTokenizedStrings and dumpHostDnsStrVector prototypes and unable to match them to definitions, so just move the definitions up to the top and drop the prototypes.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 12.0 KB
Line 
1/* $Id: HostDnsService.cpp 87578 2021-02-03 15:43:22Z vboxsync $ */
2/** @file
3 * Base class for Host DNS & Co services.
4 */
5
6/*
7 * Copyright (C) 2013-2020 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#define LOG_GROUP LOG_GROUP_MAIN_HOST
19#include <VBox/com/array.h>
20#include <VBox/com/ptr.h>
21#include <VBox/com/string.h>
22
23#include <iprt/cpp/utils.h>
24
25#include "LoggingNew.h"
26#include "VirtualBoxImpl.h"
27#include <iprt/time.h>
28#include <iprt/thread.h>
29#include <iprt/semaphore.h>
30#include <iprt/critsect.h>
31
32#include <algorithm>
33#include <set>
34#include <iprt/sanitized/string>
35#include "HostDnsService.h"
36
37
38
39static void dumpHostDnsStrVector(const std::string &prefix, const std::vector<std::string> &v)
40{
41 int i = 1;
42 for (std::vector<std::string>::const_iterator it = v.begin();
43 it != v.end();
44 ++it, ++i)
45 LogRel((" %s %d: %s\n", prefix.c_str(), i, it->c_str()));
46 if (v.empty())
47 LogRel((" no %s entries\n", prefix.c_str()));
48}
49
50static void dumpHostDnsInformation(const HostDnsInformation &info)
51{
52 dumpHostDnsStrVector("server", info.servers);
53
54 if (!info.domain.empty())
55 LogRel((" domain: %s\n", info.domain.c_str()));
56 else
57 LogRel((" no domain set\n"));
58
59 dumpHostDnsStrVector("search string", info.searchList);
60}
61
62bool HostDnsInformation::equals(const HostDnsInformation &info, uint32_t fLaxComparison) const
63{
64 bool fSameServers;
65 if ((fLaxComparison & IGNORE_SERVER_ORDER) == 0)
66 fSameServers = (servers == info.servers);
67 else
68 {
69 std::set<std::string> l(servers.begin(), servers.end());
70 std::set<std::string> r(info.servers.begin(), info.servers.end());
71
72 fSameServers = (l == r);
73 }
74
75 bool fSameDomain, fSameSearchList;
76 if ((fLaxComparison & IGNORE_SUFFIXES) == 0)
77 {
78 fSameDomain = (domain == info.domain);
79 fSameSearchList = (searchList == info.searchList);
80 }
81 else
82 fSameDomain = fSameSearchList = true;
83
84 return fSameServers && fSameDomain && fSameSearchList;
85}
86
87DECLINLINE(void) detachVectorOfString(const std::vector<std::string>& v, std::vector<com::Utf8Str> &aArray)
88{
89 aArray.resize(v.size());
90 size_t i = 0;
91 for (std::vector<std::string>::const_iterator it = v.begin(); it != v.end(); ++it, ++i)
92 aArray[i] = Utf8Str(it->c_str()); /** @todo r=bird: *it isn't necessarily UTF-8 clean!!
93 * On darwin we do silly shit like using CFStringGetSystemEncoding()
94 * that may be UTF-8 but doesn't need to be.
95 *
96 * Why on earth are we using std::string here anyway?
97 */
98}
99
100struct HostDnsServiceBase::Data
101{
102 Data(bool aThreaded)
103 : pProxy(NULL)
104 , fThreaded(aThreaded)
105 , hMonitorThreadEvent(NIL_RTSEMEVENT)
106 , hMonitorThread(NIL_RTTHREAD)
107 {}
108
109 /** Weak pointer to parent proxy object. */
110 HostDnsMonitorProxy *pProxy;
111 /** Whether the DNS monitor implementation has a dedicated monitoring thread. Optional. */
112 const bool fThreaded;
113 /** Event for the monitor thread, if any. */
114 RTSEMEVENT hMonitorThreadEvent;
115 /** Handle of the monitor thread, if any. */
116 RTTHREAD hMonitorThread;
117 /** Generic host DNS information. */
118 HostDnsInformation info;
119};
120
121struct HostDnsMonitorProxy::Data
122{
123 Data(HostDnsServiceBase *aMonitor, VirtualBox *aParent)
124 : pVirtualBox(aParent)
125 , pMonitorImpl(aMonitor)
126 , uLastExtraDataPoll(0)
127 , fLaxComparison(0)
128 , info()
129 {}
130
131 VirtualBox *pVirtualBox;
132 HostDnsServiceBase *pMonitorImpl;
133
134 uint64_t uLastExtraDataPoll;
135 uint32_t fLaxComparison;
136 HostDnsInformation info;
137};
138
139
140HostDnsServiceBase::HostDnsServiceBase(bool fThreaded)
141 : m(NULL)
142{
143 m = new HostDnsServiceBase::Data(fThreaded);
144}
145
146HostDnsServiceBase::~HostDnsServiceBase()
147{
148 if (m)
149 {
150 delete m;
151 m = NULL;
152 }
153}
154
155/* static */
156HostDnsServiceBase *HostDnsServiceBase::createHostDnsMonitor(void)
157{
158 HostDnsServiceBase *pMonitor = NULL;
159
160#if defined (RT_OS_DARWIN)
161 pMonitor = new HostDnsServiceDarwin();
162#elif defined(RT_OS_WINDOWS)
163 pMonitor = new HostDnsServiceWin();
164#elif defined(RT_OS_LINUX)
165 pMonitor = new HostDnsServiceLinux();
166#elif defined(RT_OS_SOLARIS)
167 pMonitor = new HostDnsServiceSolaris();
168#elif defined(RT_OS_FREEBSD)
169 pMonitor = new HostDnsServiceFreebsd();
170#elif defined(RT_OS_OS2)
171 pMonitor = new HostDnsServiceOs2();
172#else
173 pMonitor = new HostDnsServiceBase();
174#endif
175
176 return pMonitor;
177}
178
179HRESULT HostDnsServiceBase::init(HostDnsMonitorProxy *pProxy)
180{
181 LogRel(("HostDnsMonitor: initializing\n"));
182
183 AssertPtrReturn(pProxy, E_POINTER);
184 m->pProxy = pProxy;
185
186 if (m->fThreaded)
187 {
188 LogRel2(("HostDnsMonitor: starting thread ...\n"));
189
190 int rc = RTSemEventCreate(&m->hMonitorThreadEvent);
191 AssertRCReturn(rc, E_FAIL);
192
193 rc = RTThreadCreate(&m->hMonitorThread,
194 HostDnsServiceBase::threadMonitorProc,
195 this, 128 * _1K, RTTHREADTYPE_IO,
196 RTTHREADFLAGS_WAITABLE, "dns-monitor");
197 AssertRCReturn(rc, E_FAIL);
198
199 RTSemEventWait(m->hMonitorThreadEvent, RT_INDEFINITE_WAIT);
200
201 LogRel2(("HostDnsMonitor: thread started\n"));
202 }
203
204 return S_OK;
205}
206
207void HostDnsServiceBase::uninit(void)
208{
209 LogRel(("HostDnsMonitor: shutting down ...\n"));
210
211 if (m->fThreaded)
212 {
213 LogRel2(("HostDnsMonitor: waiting for thread ...\n"));
214
215 const RTMSINTERVAL uTimeoutMs = 30 * 1000; /* 30s */
216
217 monitorThreadShutdown(uTimeoutMs);
218
219 int rc = RTThreadWait(m->hMonitorThread, uTimeoutMs, NULL);
220 if (RT_FAILURE(rc))
221 LogRel(("HostDnsMonitor: waiting for thread failed with rc=%Rrc\n", rc));
222
223 if (m->hMonitorThreadEvent != NIL_RTSEMEVENT)
224 {
225 RTSemEventDestroy(m->hMonitorThreadEvent);
226 m->hMonitorThreadEvent = NIL_RTSEMEVENT;
227 }
228 }
229
230 LogRel(("HostDnsMonitor: shut down\n"));
231}
232
233void HostDnsServiceBase::setInfo(const HostDnsInformation &info)
234{
235 if (m->pProxy != NULL)
236 m->pProxy->notify(info);
237}
238
239void HostDnsMonitorProxy::pollGlobalExtraData(void)
240{
241 VirtualBox *pVirtualBox = m->pVirtualBox;
242 if (RT_UNLIKELY(pVirtualBox == NULL))
243 return;
244
245 uint64_t uNow = RTTimeNanoTS();
246 if (uNow - m->uLastExtraDataPoll >= RT_NS_30SEC || m->uLastExtraDataPoll == 0)
247 {
248 m->uLastExtraDataPoll = uNow;
249
250 /*
251 * Should we ignore the order of DNS servers?
252 */
253 const com::Bstr bstrHostDNSOrderIgnoreKey("VBoxInternal2/HostDNSOrderIgnore");
254 com::Bstr bstrHostDNSOrderIgnore;
255 pVirtualBox->GetExtraData(bstrHostDNSOrderIgnoreKey.raw(),
256 bstrHostDNSOrderIgnore.asOutParam());
257 uint32_t fDNSOrderIgnore = 0;
258 if (bstrHostDNSOrderIgnore.isNotEmpty())
259 {
260 if (bstrHostDNSOrderIgnore != "0")
261 fDNSOrderIgnore = HostDnsInformation::IGNORE_SERVER_ORDER;
262 }
263
264 if (fDNSOrderIgnore != (m->fLaxComparison & HostDnsInformation::IGNORE_SERVER_ORDER))
265 {
266
267 m->fLaxComparison ^= HostDnsInformation::IGNORE_SERVER_ORDER;
268 LogRel(("HostDnsMonitor: %ls=%ls\n",
269 bstrHostDNSOrderIgnoreKey.raw(),
270 bstrHostDNSOrderIgnore.raw()));
271 }
272
273 /*
274 * Should we ignore changes to the domain name or the search list?
275 */
276 const com::Bstr bstrHostDNSSuffixesIgnoreKey("VBoxInternal2/HostDNSSuffixesIgnore");
277 com::Bstr bstrHostDNSSuffixesIgnore;
278 pVirtualBox->GetExtraData(bstrHostDNSSuffixesIgnoreKey.raw(),
279 bstrHostDNSSuffixesIgnore.asOutParam());
280 uint32_t fDNSSuffixesIgnore = 0;
281 if (bstrHostDNSSuffixesIgnore.isNotEmpty())
282 {
283 if (bstrHostDNSSuffixesIgnore != "0")
284 fDNSSuffixesIgnore = HostDnsInformation::IGNORE_SUFFIXES;
285 }
286
287 if (fDNSSuffixesIgnore != (m->fLaxComparison & HostDnsInformation::IGNORE_SUFFIXES))
288 {
289
290 m->fLaxComparison ^= HostDnsInformation::IGNORE_SUFFIXES;
291 LogRel(("HostDnsMonitor: %ls=%ls\n",
292 bstrHostDNSSuffixesIgnoreKey.raw(),
293 bstrHostDNSSuffixesIgnore.raw()));
294 }
295 }
296}
297
298void HostDnsServiceBase::onMonitorThreadInitDone(void)
299{
300 if (!m->fThreaded) /* If non-threaded, bail out, nothing to do here. */
301 return;
302
303 RTSemEventSignal(m->hMonitorThreadEvent);
304}
305
306DECLCALLBACK(int) HostDnsServiceBase::threadMonitorProc(RTTHREAD, void *pvUser)
307{
308 HostDnsServiceBase *pThis = static_cast<HostDnsServiceBase *>(pvUser);
309 AssertPtrReturn(pThis, VERR_INVALID_POINTER);
310 return pThis->monitorThreadProc();
311}
312
313/* HostDnsMonitorProxy */
314HostDnsMonitorProxy::HostDnsMonitorProxy()
315 : m(NULL)
316{
317}
318
319HostDnsMonitorProxy::~HostDnsMonitorProxy()
320{
321 uninit();
322}
323
324HRESULT HostDnsMonitorProxy::init(VirtualBox* aParent)
325{
326 AssertMsgReturn(m == NULL, ("DNS monitor proxy already initialized\n"), E_FAIL);
327
328 HostDnsServiceBase *pMonitorImpl = HostDnsServiceBase::createHostDnsMonitor();
329 AssertPtrReturn(pMonitorImpl, E_OUTOFMEMORY);
330
331 Assert(m == NULL); /* Paranoia. */
332 m = new HostDnsMonitorProxy::Data(pMonitorImpl, aParent);
333 AssertPtrReturn(m, E_OUTOFMEMORY);
334
335 return m->pMonitorImpl->init(this);
336}
337
338void HostDnsMonitorProxy::uninit(void)
339{
340 if (m)
341 {
342 if (m->pMonitorImpl)
343 {
344 m->pMonitorImpl->uninit();
345
346 delete m->pMonitorImpl;
347 m->pMonitorImpl = NULL;
348 }
349
350 delete m;
351 m = NULL;
352 }
353}
354
355void HostDnsMonitorProxy::notify(const HostDnsInformation &info)
356{
357 const bool fNotify = updateInfo(info);
358 if (fNotify)
359 m->pVirtualBox->i_onHostNameResolutionConfigurationChange();
360}
361
362HRESULT HostDnsMonitorProxy::GetNameServers(std::vector<com::Utf8Str> &aNameServers)
363{
364 AssertReturn(m != NULL, E_FAIL);
365 RTCLock grab(m_LockMtx);
366
367 LogRel(("HostDnsMonitorProxy::GetNameServers:\n"));
368 dumpHostDnsStrVector("name server", m->info.servers);
369
370 detachVectorOfString(m->info.servers, aNameServers);
371
372 return S_OK;
373}
374
375HRESULT HostDnsMonitorProxy::GetDomainName(com::Utf8Str *pDomainName)
376{
377 AssertReturn(m != NULL, E_FAIL);
378 RTCLock grab(m_LockMtx);
379
380 LogRel(("HostDnsMonitorProxy::GetDomainName: %s\n",
381 m->info.domain.empty() ? "no domain set" : m->info.domain.c_str()));
382
383 *pDomainName = m->info.domain.c_str();
384
385 return S_OK;
386}
387
388HRESULT HostDnsMonitorProxy::GetSearchStrings(std::vector<com::Utf8Str> &aSearchStrings)
389{
390 AssertReturn(m != NULL, E_FAIL);
391 RTCLock grab(m_LockMtx);
392
393 LogRel(("HostDnsMonitorProxy::GetSearchStrings:\n"));
394 dumpHostDnsStrVector("search string", m->info.searchList);
395
396 detachVectorOfString(m->info.searchList, aSearchStrings);
397
398 return S_OK;
399}
400
401bool HostDnsMonitorProxy::updateInfo(const HostDnsInformation &info)
402{
403 LogRel(("HostDnsMonitor: updating information\n"));
404 RTCLock grab(m_LockMtx);
405
406 if (info.equals(m->info))
407 {
408 LogRel(("HostDnsMonitor: unchanged\n"));
409 return false;
410 }
411
412 pollGlobalExtraData();
413
414 LogRel(("HostDnsMonitor: old information\n"));
415 dumpHostDnsInformation(m->info);
416 LogRel(("HostDnsMonitor: new information\n"));
417 dumpHostDnsInformation(info);
418
419 bool fIgnore = m->fLaxComparison != 0 && info.equals(m->info, m->fLaxComparison);
420 m->info = info;
421
422 if (fIgnore)
423 {
424 LogRel(("HostDnsMonitor: lax comparison %#x, not notifying\n", m->fLaxComparison));
425 return false;
426 }
427
428 return true;
429}
430
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