VirtualBox

source: vbox/trunk/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp@ 60447

最後變更 在這個檔案從60447是 60447,由 vboxsync 提交於 9 年 前

bugref:7179. Removed auto_ptr from HostDnsServiceWin.cpp.

  • 屬性 svn:eol-style 設為 native
  • 屬性 svn:keywords 設為 Author Date Id Revision
檔案大小: 9.4 KB
 
1/* $Id: HostDnsServiceWin.cpp 60447 2016-04-12 10:03:09Z vboxsync $ */
2/** @file
3 * Host DNS listener for Windows.
4 */
5
6/*
7 * Copyright (C) 2014 Oracle Corporation
8 *
9 * This file is part of VirtualBox Open Source Edition (OSE), as
10 * available from http://www.alldomusa.eu.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#include "../HostDnsService.h"
18
19#include <VBox/com/string.h>
20#include <VBox/com/ptr.h>
21
22#include <iprt/assert.h>
23#include <iprt/err.h>
24#include <VBox/log.h>
25
26#include <Windows.h>
27#include <windns.h>
28
29#include <algorithm>
30#include <sstream>
31#include <string>
32#include <vector>
33
34struct HostDnsServiceWin::Data
35{
36 HKEY hKeyTcpipParameters;
37 bool fTimerArmed;
38
39#define DATA_SHUTDOWN_EVENT 0
40#define DATA_DNS_UPDATE_EVENT 1
41#define DATA_TIMER 2
42#define DATA_MAX_EVENT 3
43 HANDLE haDataEvent[DATA_MAX_EVENT];
44
45 Data()
46 {
47 hKeyTcpipParameters = NULL;
48 fTimerArmed = false;
49
50 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
51 haDataEvent[i] = NULL;
52 }
53
54 ~Data()
55 {
56 if (hKeyTcpipParameters != NULL)
57 RegCloseKey(hKeyTcpipParameters);
58
59 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
60 if (haDataEvent[i] != NULL)
61 CloseHandle(haDataEvent[i]);
62 }
63};
64
65
66HostDnsServiceWin::HostDnsServiceWin()
67 : HostDnsMonitor(true)
68{
69 m = new Data();
70}
71
72HostDnsServiceWin::~HostDnsServiceWin()
73{
74 if (m != NULL)
75 delete m;
76}
77
78
79HRESULT HostDnsServiceWin::init(VirtualBox *virtualbox)
80{
81 if (m == NULL)
82 return E_FAIL;
83
84 {
85 bool res = true;
86 LONG lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
87 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
88 0,
89 KEY_READ|KEY_NOTIFY,
90 &m->hKeyTcpipParameters);
91 if (lrc != ERROR_SUCCESS)
92 {
93 LogRel(("HostDnsServiceWin: failed to open key Tcpip\\Parameters (error %d)\n", lrc));
94 res = false;
95 }
96 else
97 {
98 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
99 {
100 HANDLE h;
101
102 if (i == DATA_TIMER)
103 h = CreateWaitableTimer(NULL, FALSE, NULL);
104 else
105 h = CreateEvent(NULL, TRUE, FALSE, NULL);
106
107 if (h == NULL)
108 {
109 LogRel(("HostDnsServiceWin: failed to create event (error %d)\n", GetLastError()));
110 res = false;
111 break;
112 }
113
114 m->haDataEvent[i] = h;
115 }
116 }
117 if(!res)
118 return E_FAIL;
119 }
120
121 HRESULT hrc = HostDnsMonitor::init(virtualbox);
122 if (FAILED(hrc))
123 return hrc;
124
125 return updateInfo();
126}
127
128
129void HostDnsServiceWin::monitorThreadShutdown()
130{
131 Assert(m != NULL);
132 SetEvent(m->haDataEvent[DATA_SHUTDOWN_EVENT]);
133}
134
135
136static inline int registerNotification(const HKEY& hKey, HANDLE& hEvent)
137{
138 LONG lrc = RegNotifyChangeKeyValue(hKey,
139 TRUE,
140 REG_NOTIFY_CHANGE_LAST_SET,
141 hEvent,
142 TRUE);
143 AssertMsgReturn(lrc == ERROR_SUCCESS,
144 ("Failed to register event on the key. Please debug me!"),
145 VERR_INTERNAL_ERROR);
146
147 return VINF_SUCCESS;
148}
149
150
151int HostDnsServiceWin::monitorWorker()
152{
153 Assert(m != NULL);
154
155 registerNotification(m->hKeyTcpipParameters,
156 m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
157
158 monitorThreadInitializationDone();
159
160 for (;;)
161 {
162 DWORD dwReady;
163
164 dwReady = WaitForMultipleObjects(DATA_MAX_EVENT, m->haDataEvent,
165 FALSE, INFINITE);
166
167 if (dwReady == WAIT_OBJECT_0 + DATA_SHUTDOWN_EVENT)
168 break;
169
170 if (dwReady == WAIT_OBJECT_0 + DATA_DNS_UPDATE_EVENT)
171 {
172 /*
173 * Registry updates for multiple values are not atomic, so
174 * wait a bit to avoid racing and reading partial update.
175 */
176 if (!m->fTimerArmed)
177 {
178 LARGE_INTEGER delay; /* in 100ns units */
179 delay.QuadPart = -2 * 1000 * 1000 * 10LL; /* relative: 2s */
180
181 BOOL ok = SetWaitableTimer(m->haDataEvent[DATA_TIMER], &delay,
182 0, NULL, NULL, TRUE);
183 if (ok)
184 {
185 m->fTimerArmed = true;
186 }
187 else
188 {
189 LogRel(("HostDnsServiceWin: failed to arm timer (error %d)\n", GetLastError()));
190 updateInfo();
191 }
192 }
193
194 ResetEvent(m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
195 registerNotification(m->hKeyTcpipParameters,
196 m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
197 }
198 else if (dwReady == WAIT_OBJECT_0 + DATA_TIMER)
199 {
200 m->fTimerArmed = false;
201 updateInfo();
202 }
203 else if (dwReady == WAIT_FAILED)
204 {
205 LogRel(("HostDnsServiceWin: WaitForMultipleObjects failed: error %d\n", GetLastError()));
206 return VERR_INTERNAL_ERROR;
207 }
208 else
209 {
210 LogRel(("HostDnsServiceWin: WaitForMultipleObjects unexpected return value %d\n", dwReady));
211 return VERR_INTERNAL_ERROR;
212 }
213 }
214
215 return VINF_SUCCESS;
216}
217
218
219void vappend(std::vector<std::string> &v, const std::string &s, char sep = ' ')
220{
221 if (s.empty())
222 return;
223
224 std::istringstream stream(s);
225 std::string substr;
226
227 while (std::getline(stream, substr, sep))
228 {
229 if (substr.empty())
230 continue;
231
232 if (std::find(v.cbegin(), v.cend(), substr) != v.cend())
233 continue;
234
235 v.push_back(substr);
236 }
237}
238
239
240HRESULT HostDnsServiceWin::updateInfo()
241{
242 LONG lrc;
243
244 std::string strDomain;
245 std::string strDhcpDomain;
246 std::string strSearchList; /* NB: comma separated, no spaces */
247
248 for (DWORD regIndex = 0; /**/; ++regIndex) {
249 char keyName[256];
250 DWORD cbKeyName = sizeof(keyName);
251 DWORD keyType = 0;
252 char keyData[1024];
253 DWORD cbKeyData = sizeof(keyData);
254
255 lrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex,
256 keyName, &cbKeyName, 0,
257 &keyType, (LPBYTE)keyData, &cbKeyData);
258
259 if (lrc == ERROR_NO_MORE_ITEMS)
260 break;
261
262 if (lrc == ERROR_MORE_DATA) /* buffer too small; handle? */
263 continue;
264
265 if (lrc != ERROR_SUCCESS)
266 {
267 LogRel(("HostDnsServiceWin: RegEnumValue error %d\n", (int)lrc));
268 return E_FAIL;
269 }
270
271 if (keyType != REG_SZ)
272 continue;
273
274 if (cbKeyData > 0 && keyData[cbKeyData - 1] == '\0')
275 --cbKeyData; /* don't count trailing NUL if present */
276
277 if (RTStrICmp("Domain", keyName) == 0)
278 {
279 strDomain.assign(keyData, cbKeyData);
280 Log2(("... Domain=\"%s\"\n", strDomain.c_str()));
281 }
282 else if (RTStrICmp("DhcpDomain", keyName) == 0)
283 {
284 strDhcpDomain.assign(keyData, cbKeyData);
285 Log2(("... DhcpDomain=\"%s\"\n", strDhcpDomain.c_str()));
286 }
287 else if (RTStrICmp("SearchList", keyName) == 0)
288 {
289 strSearchList.assign(keyData, cbKeyData);
290 Log2(("... SearchList=\"%s\"\n", strSearchList.c_str()));
291 }
292 }
293
294 HostDnsInformation info;
295
296 /*
297 * When name servers are configured statically it seems that the
298 * value of Tcpip\Parameters\NameServer is NOT set, inly interface
299 * specific NameServer value is (which triggers notification for
300 * us to pick up the change). Fortunately, DnsApi seems to do the
301 * right thing there.
302 */
303 DNS_STATUS status;
304 PIP4_ARRAY pIp4Array = NULL;
305
306 // NB: must be set on input it seems, despite docs' claim to the contrary.
307 DWORD cbBuffer = sizeof(&pIp4Array);
308
309 status = DnsQueryConfig(DnsConfigDnsServerList,
310 DNS_CONFIG_FLAG_ALLOC, NULL, NULL,
311 &pIp4Array, &cbBuffer);
312
313 if (status == NO_ERROR && pIp4Array != NULL)
314 {
315 for (DWORD i = 0; i < pIp4Array->AddrCount; ++i)
316 {
317 char szAddrStr[16] = "";
318 RTStrPrintf(szAddrStr, sizeof(szAddrStr), "%RTnaipv4", pIp4Array->AddrArray[i]);
319
320 Log2((" server %d: %s\n", i+1, szAddrStr));
321 info.servers.push_back(szAddrStr);
322 }
323
324 LocalFree(pIp4Array);
325 }
326
327 if (!strDomain.empty())
328 {
329 info.domain = strDomain;
330
331 info.searchList.push_back(strDomain);
332 if (!strDhcpDomain.empty() && strDhcpDomain != strDomain)
333 info.searchList.push_back(strDhcpDomain);
334 }
335 else if (!strDhcpDomain.empty())
336 {
337 info.domain = strDhcpDomain;
338 info.searchList.push_back(strDomain);
339 }
340
341 vappend(info.searchList, strSearchList, ',');
342 if (info.searchList.size() == 1)
343 info.searchList.clear();
344
345 HostDnsMonitor::setInfo(info);
346
347 return S_OK;
348}
注意: 瀏覽 TracBrowser 來幫助您使用儲存庫瀏覽器

© 2025 Oracle Support Privacy / Do Not Sell My Info Terms of Use Trademark Policy Automated Access Etiquette