VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/HostDnsService.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: 12.0 KB
Line 
1/* $Id: HostDnsService.cpp 93115 2022-01-01 11:31:46Z vboxsync $ */
2/** @file
3 * Base class for Host DNS & Co services.
4 */
5
6/*
7 * Copyright (C) 2013-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#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