VirtualBox

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

Last change on this file since 53201 was 53165, checked in by vboxsync, 11 years ago

Main/HostDnsService: brush up old Windows code. In general no
functional change is intended, but make search list handling follow
Windows behavior.

  • Property svn:eol-style set to native
  • Property svn:keywords set to Author Date Id Revision
File size: 7.6 KB
Line 
1/* $Id: HostDnsServiceWin.cpp 53165 2014-10-29 16:26:20Z 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.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#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
28#include <algorithm>
29#include <sstream>
30#include <string>
31#include <vector>
32
33struct HostDnsServiceWin::Data
34{
35 HKEY hKeyTcpipParameters;
36
37#define DATA_SHUTDOWN_EVENT 0
38#define DATA_DNS_UPDATE_EVENT 1
39#define DATA_MAX_EVENT 2
40 HANDLE haDataEvent[DATA_MAX_EVENT];
41
42 Data()
43 {
44 hKeyTcpipParameters = NULL;
45
46 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
47 haDataEvent[i] = NULL;
48 }
49
50 ~Data()
51 {
52 if (hKeyTcpipParameters != NULL)
53 RegCloseKey(hKeyTcpipParameters);
54
55 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
56 if (haDataEvent[i] != NULL)
57 CloseHandle(haDataEvent[i]);
58 }
59};
60
61
62HostDnsServiceWin::HostDnsServiceWin()
63 : HostDnsMonitor(true),
64 m(NULL)
65{
66 std::auto_ptr<Data> data(new Data());
67 LONG lrc;
68
69 lrc = RegOpenKeyExW(HKEY_LOCAL_MACHINE,
70 L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters",
71 0,
72 KEY_READ|KEY_NOTIFY,
73 &data->hKeyTcpipParameters);
74 if (lrc != ERROR_SUCCESS)
75 {
76 LogRel(("HostDnsServiceWin: failed to open key Tcpip\\Parameters (error %d)\n", lrc));
77 return;
78 }
79
80 for (size_t i = 0; i < DATA_MAX_EVENT; ++i)
81 {
82 data->haDataEvent[i] = CreateEvent(NULL, TRUE, FALSE, NULL);
83 if (data->haDataEvent[i] == NULL)
84 {
85 LogRel(("HostDnsServiceWin: failed to create event (error %d)\n", GetLastError()));
86 return;
87 }
88 }
89
90 m = data.release();
91}
92
93
94HostDnsServiceWin::~HostDnsServiceWin()
95{
96 if (m != NULL)
97 delete m;
98}
99
100
101HRESULT HostDnsServiceWin::init()
102{
103 if (m == NULL)
104 return E_FAIL;
105
106 HRESULT hrc = HostDnsMonitor::init();
107 if (FAILED(hrc))
108 return hrc;
109
110 return updateInfo();
111}
112
113
114void HostDnsServiceWin::monitorThreadShutdown()
115{
116 Assert(m != NULL);
117 SetEvent(m->haDataEvent[DATA_SHUTDOWN_EVENT]);
118}
119
120
121static inline int registerNotification(const HKEY& hKey, HANDLE& hEvent)
122{
123 LONG lrc = RegNotifyChangeKeyValue(hKey,
124 TRUE,
125 REG_NOTIFY_CHANGE_LAST_SET,
126 hEvent,
127 TRUE);
128 AssertMsgReturn(lrc == ERROR_SUCCESS,
129 ("Failed to register event on the key. Please debug me!"),
130 VERR_INTERNAL_ERROR);
131
132 return VINF_SUCCESS;
133}
134
135
136int HostDnsServiceWin::monitorWorker()
137{
138 Assert(m != NULL);
139
140 registerNotification(m->hKeyTcpipParameters,
141 m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
142
143 monitorThreadInitializationDone();
144
145 for (;;)
146 {
147 DWORD dwReady;
148
149 dwReady = WaitForMultipleObjects(DATA_MAX_EVENT, m->haDataEvent,
150 FALSE, INFINITE);
151
152 if (dwReady == WAIT_OBJECT_0 + DATA_SHUTDOWN_EVENT)
153 break;
154
155 if (dwReady == WAIT_OBJECT_0 + DATA_DNS_UPDATE_EVENT)
156 {
157 updateInfo();
158 notifyAll();
159
160 ResetEvent(m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
161 registerNotification(m->hKeyTcpipParameters,
162 m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
163
164 }
165 else
166 {
167 if (dwReady == WAIT_FAILED)
168 LogRel(("HostDnsServiceWin: WaitForMultipleObjects failed: error %d\n", GetLastError()));
169 else
170 LogRel(("HostDnsServiceWin: WaitForMultipleObjects unexpected return value %d\n", dwReady));
171 return VERR_INTERNAL_ERROR;
172 }
173 }
174
175 return VINF_SUCCESS;
176}
177
178
179void vappend(std::vector<std::string> &v, const std::string &s, char sep = ' ')
180{
181 if (s.empty())
182 return;
183
184 std::istringstream stream(s);
185 std::string substr;
186
187 while (std::getline(stream, substr, sep))
188 {
189 if (substr.empty())
190 continue;
191
192 if (std::find(v.cbegin(), v.cend(), substr) != v.cend())
193 continue;
194
195 v.push_back(substr);
196 }
197}
198
199
200HRESULT HostDnsServiceWin::updateInfo()
201{
202 LONG lrc;
203
204 std::string strNameServer;
205 std::string strDomain;
206 std::string strDhcpNameServer;
207 std::string strDhcpDomain;
208 std::string strSearchList; /* NB: comma separated, no spaces */
209
210 for (DWORD regIndex = 0; /**/; ++regIndex) {
211 char keyName[256];
212 DWORD cbKeyName = sizeof(keyName);
213 DWORD keyType = 0;
214 char keyData[1024];
215 DWORD cbKeyData = sizeof(keyData);
216
217 lrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex,
218 keyName, &cbKeyName, 0,
219 &keyType, (LPBYTE)keyData, &cbKeyData);
220
221 if (lrc == ERROR_NO_MORE_ITEMS)
222 break;
223
224 if (lrc == ERROR_MORE_DATA) /* buffer too small; handle? */
225 continue;
226
227 if (lrc != ERROR_SUCCESS)
228 {
229 LogRel(("HostDnsServiceWin: RegEnumValue error %d\n", (int)lrc));
230 return E_FAIL;
231 }
232
233 if (keyType != REG_SZ)
234 continue;
235
236 if (cbKeyData > 0 && keyData[cbKeyData - 1] == '\0')
237 --cbKeyData; /* don't count trailing NUL if present */
238
239 if (RTStrICmp("NameServer", keyName) == 0)
240 {
241 strNameServer.assign(keyData, cbKeyData);
242 Log2(("... NameServer=\"%s\"\n", strNameServer.c_str()));
243 }
244 else if (RTStrICmp("Domain", keyName) == 0)
245 {
246 strDomain.assign(keyData, cbKeyData);
247 Log2(("... Domain=\"%s\"\n", strDomain.c_str()));
248 }
249 else if (RTStrICmp("DhcpNameServer", keyName) == 0)
250 {
251 strDhcpNameServer.assign(keyData, cbKeyData);
252 Log2(("... DhcpNameServer=\"%s\"\n", strDhcpNameServer.c_str()));
253 }
254 else if (RTStrICmp("DhcpDomain", keyName) == 0)
255 {
256 strDhcpDomain.assign(keyData, cbKeyData);
257 Log2(("... DhcpDomain=\"%s\"\n", strDhcpDomain.c_str()));
258 }
259 else if (RTStrICmp("SearchList", keyName) == 0)
260 {
261 strSearchList.assign(keyData, cbKeyData);
262 Log2(("... SearchList=\"%s\"\n", strSearchList.c_str()));
263 }
264 }
265
266 HostDnsInformation info;
267
268 if (!strNameServer.empty())
269 vappend(info.servers, strNameServer);
270 else if (!strDhcpNameServer.empty())
271 vappend(info.servers, strDhcpNameServer);
272
273 if (!strDomain.empty())
274 {
275 info.domain = strDomain;
276
277 info.searchList.push_back(strDomain);
278 if (!strDhcpDomain.empty() && strDhcpDomain != strDomain)
279 info.searchList.push_back(strDhcpDomain);
280 }
281 else if (!strDhcpDomain.empty())
282 {
283 info.domain = strDhcpDomain;
284 info.searchList.push_back(strDomain);
285 }
286
287 vappend(info.searchList, strSearchList, ',');
288 if (info.searchList.size() == 1)
289 info.searchList.clear();
290
291 HostDnsMonitor::setInfo(info);
292
293 return S_OK;
294}
Note: See TracBrowser for help on using the repository browser.

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