VirtualBox

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

Last change on this file since 86714 was 85271, checked in by vboxsync, 4 years ago

Main/HostDnsServiceDarwin.cpp,++: Wrong index types (must use CFIndex). Left a number of TODOs behind. bugref:9790

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