Changeset 53159 in vbox
- Timestamp:
- Oct 28, 2014 2:51:59 PM (11 years ago)
- svn:sync-xref-src-repo-rev:
- 96695
- Location:
- trunk/src/VBox/Main/src-server
- Files:
-
- 2 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-server/HostDnsService.h
r53151 r53159 146 146 # endif 147 147 # ifdef RT_OS_WINDOWS 148 /* Maximum size of Windows registry key (according to MSDN). */149 #define VBOX_KEY_NAME_LEN_MAX (255)150 151 148 class HostDnsServiceWin : public HostDnsMonitor 152 149 { 153 public:150 public: 154 151 HostDnsServiceWin(); 155 152 ~HostDnsServiceWin(); 156 157 153 HRESULT init(); 158 154 159 protected:155 protected: 160 156 virtual void monitorThreadShutdown(); 161 157 virtual int monitorWorker(); 162 158 163 private: 164 /* 165 * Bit flags to determine what was exactly was changed when 166 * Windows triggered event notification. 167 */ 168 enum { 169 VBOX_EVENT_NO_CHANGES = 0, 170 VBOX_EVENT_SERVERS_CHANGED = RT_BIT(1), 171 VBOX_EVENT_DOMAIN_CHANGED = RT_BIT(2), 172 VBOX_EVENT_SEARCHLIST_CHANGED = RT_BIT(3), 173 }; 174 175 /* m_aWarehouse array offsets. */ 176 enum { 177 VBOX_OFFSET_SHUTDOWN_EVENT = 0, 178 VBOX_OFFSET_TREE_EVENT = 1, 179 VBOX_OFFSET_SUBTREE_EVENTS = 2, 180 }; 181 182 /* 183 * This structure is used in order to link Windows registry key 184 * with an event which is generated once the key has been changed 185 * (when interface has updated its DNS setting) or one of the 186 * sub-keys has been deleted or added (when interface added or 187 * deleted). 188 */ 189 struct Item 190 { 191 HKEY hKey; /* Key handle. */ 192 HANDLE hEvent; /* Event handle. */ 193 wchar_t wcsInterface[VBOX_KEY_NAME_LEN_MAX]; /* Path to key within Windows registry. */ 194 }; 195 196 197 static const wchar_t pwcKeyRoot[]; 198 199 /* 200 * This flag indicates whether constructor performed 201 * initialization correctly. If not set, monitorWorker() will not 202 * perform any action and will be terminated as soon as there will 203 * be an attempt to run it. 204 */ 205 bool m_fInitialized; 206 207 /* 208 * Keys and events storage. Size of this vector should not be 209 * greater than MAXIMUM_WAIT_OBJECTS because this is exactly 210 * maximum amount of events which we allowed to wait for. 211 */ 212 std::vector<struct Item> m_aWarehouse; 213 214 /* Cached host network configuration. */ 215 HostDnsInformation m_hostInfoCache; 216 217 218 /* Do actual unsubscription for given item. */ 219 bool releaseWarehouseItem(int idxItem); 220 221 /* Release all allocated resources and unsubscribe from everything. */ 222 void releaseResources(); 223 224 /* Remove subscription from DNS change notifications and release corresponding resources. */ 225 bool dropSubTreeNotifications(); 226 227 /* Create & add event into the list of events we monitor to. */ 228 bool subscribeTo(const wchar_t *wcsPath, const wchar_t *wcsInterface, DWORD fFilter); 229 230 /* Subscribe to DNS changes. */ 231 bool enumerateSubTree(); 232 233 /* Get plain array of event handles. */ 234 void getEventHandles(HANDLE *ahEvents); 235 void extendVectorWithStrings(std::vector<std::string>& pVectorToExtend, const std::wstring &wcsParameter); 236 237 HRESULT updateInfo(uint8_t *fWhatsChanged); 159 private: 160 void strList2List(std::vector<std::string>& lst, char *strLst); 161 HRESULT updateInfo(); 162 163 private: 164 struct Data; 165 Data *m; 238 166 }; 239 167 # endif -
trunk/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp
r53154 r53159 1 /* $Id$ */ 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 1 /* -*- indent-tabs-mode: nil; -*- */ 18 2 #include <VBox/com/string.h> 19 3 #include <VBox/com/ptr.h> 20 #include <VBox/log.h> 4 21 5 22 6 #include <iprt/assert.h> … … 26 10 27 11 #include <string> 28 #include <sstream>29 12 #include <vector> 30 13 #include "../HostDnsService.h" 31 14 32 /* In order to monitor DNS setting updates we need to receive notification about 33 * Computer\HKEY_LOCAL_MACHINE\SYSTEM\CurrentControlSet\Services\Tcpip\Parameters\Interfaces\* keys changes. 34 * Since it is not possible to use patterns when subscribing key changes, we need to find valid paths for all such 35 * keys manually and subscribe to changes one by one (see enumerateSubTree()). */ 36 const wchar_t HostDnsServiceWin::pwcKeyRoot[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces"; 37 38 39 HostDnsServiceWin::HostDnsServiceWin() 40 : HostDnsMonitor(true), 41 m_aWarehouse(), 42 m_hostInfoCache(), 43 m_fInitialized(false) 44 { 45 /* Add monitor destroy event. 46 * This event should have index '0' at the events array in order to separate it from 47 * DNS and tree change events. When this event occurs all resources should be released. */ 48 if (subscribeTo(NULL, NULL, 0)) 15 struct HostDnsServiceWin::Data 16 { 17 HostDnsServiceWin::Data(){} 18 HKEY hKeyTcpipParameters; 19 #define DATA_DNS_UPDATE_EVENT 0 20 #define DATA_SHUTDOWN_EVENT 1 21 #define DATA_MAX_EVENT 2 22 HANDLE haDataEvent[DATA_MAX_EVENT]; 23 }; 24 25 static inline int registerNotification(const HKEY& hKey, HANDLE& hEvent) 26 { 27 LONG lrc = RegNotifyChangeKeyValue(hKey, 28 TRUE, 29 REG_NOTIFY_CHANGE_LAST_SET, 30 hEvent, 31 TRUE); 32 AssertMsgReturn(lrc == ERROR_SUCCESS, 33 ("Failed to register event on the key. Please debug me!"), 34 VERR_INTERNAL_ERROR); 35 36 return VINF_SUCCESS; 37 } 38 39 HostDnsServiceWin::HostDnsServiceWin():HostDnsMonitor(true), m(NULL) 40 { 41 m = new Data(); 42 43 m->haDataEvent[DATA_DNS_UPDATE_EVENT] = CreateEvent(NULL, 44 TRUE, FALSE, NULL); 45 AssertReleaseMsg(m->haDataEvent[DATA_DNS_UPDATE_EVENT], 46 ("Failed to create event for DNS event (%d)\n", GetLastError())); 47 48 m->haDataEvent[DATA_SHUTDOWN_EVENT] = CreateEvent(NULL, 49 TRUE, FALSE, NULL); 50 AssertReleaseMsg(m->haDataEvent[DATA_SHUTDOWN_EVENT], 51 ("Failed to create event for Shutdown signal (%d)\n", GetLastError())); 52 53 LONG lrc = RegOpenKeyEx(HKEY_LOCAL_MACHINE, 54 TEXT("SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters"), 55 0, KEY_READ|KEY_NOTIFY, &m->hKeyTcpipParameters); 56 AssertReleaseMsg(lrc == ERROR_SUCCESS, 57 ("Failed to open Registry Key for read and update notifications (%d)\n", 58 GetLastError())); 59 } 60 61 62 HostDnsServiceWin::~HostDnsServiceWin() 63 { 64 if (m && !m->hKeyTcpipParameters) 49 65 { 50 /* Add registry tree change event and corresponding key. 51 * This event should have index '1' at the events array in order to separate it from DNS events. 52 * When this event occurs it means there are changes in the list of available network interfaces. 53 * Network interfaces should be re-enumerated, all DNS events and keys data should re-initialized. */ 54 if (subscribeTo(pwcKeyRoot, NULL, REG_NOTIFY_CHANGE_NAME)) 55 { 56 /* Enumerate all available network interfaces, create events and corresponding keys and perform subscription. */ 57 if (enumerateSubTree()) 58 { 59 updateInfo(NULL); 60 m_fInitialized = true; 61 return; 62 } 63 else 64 LogRel(("WARNING: cannot set up monitor properly (3); monitor now disabled.\n")); 65 } 66 else 67 /* Too bad we can't even subscribe to notifications about network interfaces changes. */ 68 LogRel(("WARNING: cannot set up monitor properly (2); monitor now disabled.\n")); 66 RegCloseKey(m->hKeyTcpipParameters); 67 m->hKeyTcpipParameters = 0; 68 69 CloseHandle(m->haDataEvent[DATA_DNS_UPDATE_EVENT]); 70 CloseHandle(m->haDataEvent[DATA_SHUTDOWN_EVENT]); 71 72 delete m; 73 74 m = NULL; 69 75 } 70 else71 /* Too bad we can't even subscribe to destroy event. */72 LogRel(("WARNING: cannot set up monitor properly (1); monitor now disabled.\n"));73 74 releaseResources();75 }76 77 78 HostDnsServiceWin::~HostDnsServiceWin()79 {80 monitorThreadShutdown();81 releaseResources();82 m_fInitialized = false;83 }84 85 86 bool HostDnsServiceWin::releaseWarehouseItem(int idxItem)87 {88 bool rc = true;89 /* We do not check if idxItem is in valid range of m_aWarehouse here90 * (a bit of performance optimization), so make sure you provided a valid value! */91 struct Item oTmpItem = m_aWarehouse[idxItem];92 93 /* Non-zero return code means ResetEvent() succeeded. */94 rc = ResetEvent(oTmpItem.hEvent) != 0;95 if (!rc) LogRel(("Failed to reset event (idxItem=%d); monitor unstable (rc=%d).\n", idxItem, GetLastError()));96 CloseHandle(oTmpItem.hEvent);97 oTmpItem.hEvent = NULL;98 99 RegCloseKey(oTmpItem.hKey);100 oTmpItem.hKey = NULL;101 102 Log2(("Unsubscribed from %ls notifications\n", oTmpItem.wcsInterface));103 104 m_aWarehouse.erase(m_aWarehouse.begin() + idxItem);105 106 return rc;107 }108 109 110 bool HostDnsServiceWin::dropSubTreeNotifications()111 {112 bool rc = true;113 /* Any sub-tree events we subscribed? */114 if (m_aWarehouse.size() > VBOX_OFFSET_SUBTREE_EVENTS)115 /* Going from the end to the beginning. */116 for (int idxItem = (int)m_aWarehouse.size() - 1; idxItem >= VBOX_OFFSET_SUBTREE_EVENTS; idxItem--)117 rc &= releaseWarehouseItem(idxItem);118 119 size_t cElementsLeft = m_aWarehouse.size();120 if (cElementsLeft != VBOX_OFFSET_SUBTREE_EVENTS)121 {122 LogRel(("DNS monitor unstable; %d events left after dropping.\n", (int)cElementsLeft - VBOX_OFFSET_SUBTREE_EVENTS));123 return false;124 }125 126 return rc;127 }128 129 130 void HostDnsServiceWin::releaseResources()131 {132 /* First, drop notifications subscription for sub-tree keys. */133 dropSubTreeNotifications();134 135 /* Then release notification about tree structure changes. */136 if (m_aWarehouse.size() > VBOX_OFFSET_TREE_EVENT)137 releaseWarehouseItem(VBOX_OFFSET_TREE_EVENT);138 139 /* Release shutdown event. */140 if (m_aWarehouse.size() > VBOX_OFFSET_SHUTDOWN_EVENT)141 releaseWarehouseItem(VBOX_OFFSET_SHUTDOWN_EVENT);142 143 AssertReturnVoid(m_aWarehouse.size() == 0);144 }145 146 147 bool HostDnsServiceWin::subscribeTo(const wchar_t *wcsPath, const wchar_t *wcsInterface, DWORD fFilter)148 {149 HKEY hTmpKey = NULL;150 HANDLE hTmpEvent = NULL;151 152 /* Do not add more than MAXIMUM_WAIT_OBJECTS items to the array due to WaitForMultipleObjects() limitation. */153 if ((m_aWarehouse.size() + 1 /* the array size if we would add an extra item */ ) > MAXIMUM_WAIT_OBJECTS)154 {155 LogRel(("Too many items to monitor.\n"));156 return false;157 }158 159 hTmpEvent = CreateEvent(NULL, TRUE, FALSE, NULL);160 if (!hTmpEvent)161 return false;162 163 /* wcsPath might not be specified if we want to subscribe to the termination event. In this case164 * it is assumed that this is the first issued subscription request (i.e., m_aWarehouse.size() == 0). */165 if (wcsPath)166 {167 LONG rc;168 /* Open registry key itself. */169 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, wcsPath, 0, KEY_READ | KEY_NOTIFY, &hTmpKey);170 if (rc == ERROR_SUCCESS)171 {172 /* Link registry key and notification event. */173 rc = RegNotifyChangeKeyValue(hTmpKey, TRUE, fFilter, hTmpEvent, TRUE);174 if (rc != ERROR_SUCCESS)175 {176 /* Don't leak! */177 RegCloseKey(hTmpKey);178 LogRel(("Unable to register key notification (rc=0x%X).\n", rc));179 }180 }181 else182 LogRel(("Unable to open key (rc=0x%X)\n", rc));183 184 /* All good so far? */185 if (rc != ERROR_SUCCESS)186 {187 LogRel(("WARNING: unable to set up %ls registry key notifications.\n", wcsPath));188 CloseHandle(hTmpEvent);189 return false;190 }191 }192 else if (m_aWarehouse.size() > 0)193 {194 LogRel(("Subscription to termination event already established.\n"));195 CloseHandle(hTmpEvent);196 return false;197 }198 199 /* Finally, construct array item and queue it. */200 struct Item oTmpItem = { hTmpKey, hTmpEvent, NULL };201 202 /* Sub-tree keys should provide interface name (UUID). This is needed in order to203 * collect all useful network settings to HostDnsInformation storage object to provide it to parent class. */204 if (wcsInterface)205 wcscpy(oTmpItem.wcsInterface, wcsInterface);206 207 if (wcsPath)208 Log2(("Subscription to %ls established.\n", wcsPath));209 210 m_aWarehouse.push_back(oTmpItem);211 212 return true;213 }214 215 216 bool HostDnsServiceWin::enumerateSubTree()217 {218 LONG rc = 0;219 HKEY hTmpKey;220 DWORD cSubKeys = 0;221 DWORD cbSubKeyNameMax = 0;222 223 /* Enumerate all the available interfaces. */224 rc = RegOpenKeyExW(HKEY_LOCAL_MACHINE, pwcKeyRoot, 0, KEY_READ, &hTmpKey);225 if (rc == ERROR_SUCCESS)226 {227 /* Get info about amount of available network interfaces. */228 rc = RegQueryInfoKeyW(hTmpKey, NULL, NULL, NULL, &cSubKeys, &cbSubKeyNameMax, NULL, NULL, NULL, NULL, NULL, NULL);229 if (rc == ERROR_SUCCESS)230 {231 /* Now iterate over interfaces if:232 * 1) there are interfaces available and233 * 2) maximum length of an interface name conforms to our buffer allocation size. */234 if (cSubKeys > 0 && cbSubKeyNameMax <= VBOX_KEY_NAME_LEN_MAX)235 {236 wchar_t sSubKeyName[VBOX_KEY_NAME_LEN_MAX];237 for (DWORD idxSubKey = 0; idxSubKey < cSubKeys; idxSubKey++)238 {239 rc = RegEnumKeyW(hTmpKey, idxSubKey, sSubKeyName, VBOX_KEY_NAME_LEN_MAX);240 if (rc == ERROR_SUCCESS)241 {242 /* Since we already know interface name (actually UUID), construct full registry path here. */243 wchar_t sSubKeyFullPath[VBOX_KEY_NAME_LEN_MAX];244 RT_ZERO(sSubKeyFullPath);245 wcscpy(sSubKeyFullPath, pwcKeyRoot);246 rc = wcscat_s(sSubKeyFullPath, VBOX_KEY_NAME_LEN_MAX, L"\\");247 rc |= wcscat_s(sSubKeyFullPath, VBOX_KEY_NAME_LEN_MAX, sSubKeyName);248 if (rc == 0)249 subscribeTo(sSubKeyFullPath, sSubKeyName, REG_NOTIFY_CHANGE_LAST_SET);250 }251 else252 LogRel(("Unable to open interfaces list (1).\n"));253 }254 RegCloseKey(hTmpKey);255 return true;256 }257 else258 LogRel(("Unable to open interfaces list (2).\n"));259 }260 else261 LogRel(("Unable to open interfaces list (3).\n"));262 RegCloseKey(hTmpKey);263 }264 else265 LogRel(("Unable to open interfaces list (4).\n"));266 return false;267 76 } 268 77 … … 273 82 AssertComRCReturn(hrc, hrc); 274 83 275 return updateInfo( NULL);84 return updateInfo(); 276 85 } 277 86 … … 279 88 void HostDnsServiceWin::monitorThreadShutdown() 280 89 { 281 AssertReturnVoid(m_aWarehouse.size() > VBOX_OFFSET_SHUTDOWN_EVENT); 282 SetEvent(m_aWarehouse[VBOX_OFFSET_SHUTDOWN_EVENT].hEvent); 283 } 284 285 286 void HostDnsServiceWin::extendVectorWithStrings(std::vector<std::string> &pVectorToExtend, const std::wstring &wcsParameter) 287 { 288 std::wstringstream wcsStream(wcsParameter); 289 std::wstring wcsSubString; 290 291 while (std::getline(wcsStream, wcsSubString, L' ')) 292 { 293 std::string str = std::_Narrow_str(wcsSubString); 294 pVectorToExtend.push_back(str); 295 } 296 } 297 298 #ifdef DEBUG 299 static void hostDnsWinDumpList(const std::vector<std::string> &awcszValues) 300 { 301 for (int idxItem = 0; idxItem < awcszValues.size(); idxItem++) 302 { 303 LogRel(("%s\n", awcszValues[idxItem].c_str())); 304 } 305 } 306 #endif /* DEBUG */ 307 308 309 HRESULT HostDnsServiceWin::updateInfo(uint8_t *fWhatsChanged) 310 { 311 HostDnsInformation pHostDnsInfo; 312 RT_ZERO(pHostDnsInfo); 313 314 /* Any interfaces available? */ 315 if (m_aWarehouse.size() > VBOX_OFFSET_SUBTREE_EVENTS) 316 { 317 /* Walk across all the available interfaces and collect network configuration data: 318 * domain name, name servers and search list. */ 319 for (int idxKey = VBOX_OFFSET_SUBTREE_EVENTS; idxKey < m_aWarehouse.size(); idxKey++) 320 { 321 LONG rc; 322 323 /* Get number of key values. */ 324 DWORD cValues = 0; 325 rc = RegQueryInfoKeyW(m_aWarehouse[idxKey].hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cValues, NULL, NULL, NULL, NULL); 326 if (rc == ERROR_SUCCESS) 327 { 328 for (DWORD idxValue = 0; idxValue < cValues; idxValue++) 329 { 330 wchar_t wcsValueName[VBOX_KEY_NAME_LEN_MAX]; 331 DWORD cbValueName = VBOX_KEY_NAME_LEN_MAX; 332 wchar_t wcsData[VBOX_KEY_NAME_LEN_MAX]; 333 DWORD cbData = VBOX_KEY_NAME_LEN_MAX; 334 335 /* Walk across all the properties of given interface. */ 336 rc = RegEnumValueW(m_aWarehouse[idxKey].hKey, idxValue, wcsValueName, &cbValueName, 0, NULL, (LPBYTE)wcsData, &cbData); 337 if (rc == ERROR_SUCCESS) 338 { 339 340 if (( wcscmp(wcsValueName, L"Domain") == 0 341 || wcscmp(wcsValueName, L"DhcpDomain") == 0) 342 && wcslen(wcsData) > 0) 343 { 344 /* We rely on that fact that Windows host cannot be a member of more than one domain in the same time! */ 345 if (pHostDnsInfo.domain.empty()) 346 pHostDnsInfo.domain = std::_Narrow_str(std::wstring(wcsData)); 347 } 348 else if (( wcscmp(wcsValueName, L"NameServer") == 0 349 || wcscmp(wcsValueName, L"DhcpNameServer") == 0) 350 && wcslen(wcsData) > 0) 351 { 352 extendVectorWithStrings(pHostDnsInfo.servers, std::wstring(wcsData)); 353 } 354 else if (wcscmp(wcsValueName, L"SearchList") == 0 355 && wcslen(wcsData) > 0) 356 { 357 extendVectorWithStrings(pHostDnsInfo.searchList, std::wstring(wcsData)); 358 } 359 } 360 } 361 } 362 } 363 364 uint8_t fChanged = VBOX_EVENT_NO_CHANGES; 365 /* Compare cached network settings and newly obtained ones. */ 366 if (pHostDnsInfo.servers != m_hostInfoCache.servers) 367 { 368 #ifdef DEBUG 369 LogRel(("Servers changed from:\n")); 370 hostDnsWinDumpList(m_hostInfoCache.servers); 371 LogRel(("to:\n")); 372 hostDnsWinDumpList(pHostDnsInfo.servers); 373 #endif /* DEBUG */ 374 fChanged |= VBOX_EVENT_SERVERS_CHANGED; 375 } 376 377 if (pHostDnsInfo.domain != m_hostInfoCache.domain) 378 { 379 #ifdef DEBUG 380 LogRel(("Domain changed: [%s]->[%s].\n", 381 m_hostInfoCache.domain.empty() ? "NONE" : m_hostInfoCache.domain.c_str(), 382 pHostDnsInfo.domain.c_str())); 383 #endif /* DEBUG */ 384 fChanged |= VBOX_EVENT_DOMAIN_CHANGED; 385 } 386 387 if (pHostDnsInfo.searchList != m_hostInfoCache.searchList) 388 { 389 #ifdef DEBUG 390 LogRel(("SearchList changed from:\n")); 391 hostDnsWinDumpList(m_hostInfoCache.searchList); 392 LogRel(("to:\n")); 393 hostDnsWinDumpList(pHostDnsInfo.searchList); 394 #endif /* DEBUG */ 395 fChanged |= VBOX_EVENT_SEARCHLIST_CHANGED; 396 } 397 398 /* Provide info about changes if requested. */ 399 if (fWhatsChanged) 400 *fWhatsChanged = fChanged; 401 402 /* Update host network configuration cache. */ 403 m_hostInfoCache.servers.clear(); 404 m_hostInfoCache.servers = pHostDnsInfo.servers; 405 m_hostInfoCache.domain.clear(); 406 m_hostInfoCache.domain.assign(pHostDnsInfo.domain); 407 m_hostInfoCache.searchList.clear(); 408 m_hostInfoCache.searchList = pHostDnsInfo.searchList; 409 410 HostDnsMonitor::setInfo(pHostDnsInfo); 411 } 412 413 return S_OK; 414 } 415 416 417 void HostDnsServiceWin::getEventHandles(HANDLE *ahEvents) 418 { 419 AssertReturnVoid(m_aWarehouse.size() > 0); 420 for (int idxHandle = 0; idxHandle < m_aWarehouse.size(); idxHandle++) 421 ahEvents[idxHandle] = m_aWarehouse[idxHandle].hEvent; 90 SetEvent(m->haDataEvent[DATA_SHUTDOWN_EVENT]); 422 91 } 423 92 … … 425 94 int HostDnsServiceWin::monitorWorker() 426 95 { 96 registerNotification(m->hKeyTcpipParameters, 97 m->haDataEvent[DATA_DNS_UPDATE_EVENT]); 98 427 99 monitorThreadInitializationDone(); 428 100 429 uint8_t fWhatsChanged = VBOX_EVENT_NO_CHANGES; 430 431 if (!m_fInitialized) 432 { 433 LogRel(("Host DNS monitor was not initialized properly.\n")); 434 return VERR_INTERNAL_ERROR; 435 } 436 437 HANDLE ahEvents[MAXIMUM_WAIT_OBJECTS]; 438 101 DWORD dwRc; 439 102 while (true) 440 103 { 441 /* Each new iteration we need to update event handles list we monitor. */ 442 RT_ZERO(ahEvents); 443 getEventHandles(ahEvents); 444 445 DWORD rc = WaitForMultipleObjects((DWORD)m_aWarehouse.size(), ahEvents, FALSE, INFINITE); 446 447 AssertMsgReturn(rc != WAIT_FAILED, 104 dwRc = WaitForMultipleObjects(DATA_MAX_EVENT, 105 m->haDataEvent, 106 FALSE, 107 INFINITE); 108 AssertMsgReturn(dwRc != WAIT_FAILED, 448 109 ("WaitForMultipleObjects failed (%d) to wait! Please debug", 449 110 GetLastError()), VERR_INTERNAL_ERROR); 450 111 451 /* Shutdown requested. */ 452 if (rc == (WAIT_OBJECT_0 + VBOX_OFFSET_SHUTDOWN_EVENT)) break; 453 /* Interfaces amount changed. */ 454 else if (rc == (WAIT_OBJECT_0 + VBOX_OFFSET_TREE_EVENT)) 455 { 456 Log2(("Network interfaces amount changed.\n")); 457 458 /* Drop interface events. */ 459 if (dropSubTreeNotifications()) 460 { 461 /* Drop event which is corresponds to interfaces tree changes. */ 462 if (releaseWarehouseItem(VBOX_OFFSET_TREE_EVENT)) 463 { 464 /* Restart interface tree monitoring. */ 465 if (subscribeTo(pwcKeyRoot, NULL, REG_NOTIFY_CHANGE_NAME)) 466 { 467 /* Restart interface events. */ 468 if (enumerateSubTree()) 469 { 470 Log2(("Monitor restarted successfully.\n")); 471 fWhatsChanged = VBOX_EVENT_NO_CHANGES; 472 updateInfo(&fWhatsChanged); 473 if (fWhatsChanged & VBOX_EVENT_SERVERS_CHANGED) 474 { 475 LogRel(("Notification sent (1).\n")); 476 notifyAll(); 477 } 478 continue; 479 } 480 else 481 LogRel(("Monitor unstable: failed to subscribe network configuration changes.\n")); 482 } 483 else 484 LogRel(("Monitor unstable: failed to subscribe interface changes.\n")); 485 } 486 else 487 LogRel(("Monitor unstable: failed to unsubscribe from interfaces amount changes.\n")); 488 } 489 else 490 LogRel(("Monitor unstable: failed to unsubscribe from previous notifications.\n")); 491 492 /* If something went wrong, we break monitoring. */ 112 if ((dwRc - WAIT_OBJECT_0) == DATA_DNS_UPDATE_EVENT) 113 { 114 updateInfo(); 115 notifyAll(); 116 ResetEvent(m->haDataEvent[DATA_DNS_UPDATE_EVENT]); 117 registerNotification(m->hKeyTcpipParameters, 118 m->haDataEvent[DATA_DNS_UPDATE_EVENT]); 119 120 } 121 else if ((dwRc - WAIT_OBJECT_0) == DATA_SHUTDOWN_EVENT) 122 { 493 123 break; 494 495 }496 /* DNS update events range. */497 else if (rc >= (WAIT_OBJECT_0 + VBOX_OFFSET_SUBTREE_EVENTS) &&498 rc < (WAIT_OBJECT_0 + m_aWarehouse.size()))499 {500 Log2(("Network setting has changed at interface %ls.\n", m_aWarehouse[rc - WAIT_OBJECT_0].wcsInterface));501 502 /* Drop previous notifications first. */503 if (dropSubTreeNotifications())504 {505 /* Re-subscribe. */506 if (enumerateSubTree())507 {508 Log2(("Restart monitoring.\n"));509 fWhatsChanged = VBOX_EVENT_NO_CHANGES;510 updateInfo(&fWhatsChanged);511 if (fWhatsChanged & VBOX_EVENT_SERVERS_CHANGED)512 {513 LogRel(("Notification sent (2).\n"));514 notifyAll();515 }516 continue;517 }518 else519 LogRel(("WARNING: Monitor unstable: unable to re-subscribe to notifications.\n"));520 }521 else522 LogRel(("WARNING: Monitor unstable: failed to unsubscribe from previous notifications.\n"));523 524 /* If something went wrong, we stop monitoring. */525 break;526 124 } 527 125 else 528 AssertMsgFailedReturn(("WaitForMultipleObjects returns out of bound (%d) index %d. Please debug!\n", m_aWarehouse.size(), rc), VERR_INTERNAL_ERROR); 126 { 127 AssertMsgFailedReturn( 128 ("WaitForMultipleObjects returns out of bound index %d. Please debug!", 129 dwRc), 130 VERR_INTERNAL_ERROR); 131 } 529 132 } 530 LogRel(("Monitor thread exited.\n"));531 133 return VINF_SUCCESS; 532 134 } 135 136 137 HRESULT HostDnsServiceWin::updateInfo() 138 { 139 HRESULT hrc; 140 DWORD regIndex; 141 BYTE abDomain[256]; 142 BYTE abNameServers[256]; 143 BYTE abSearchList[256]; 144 145 RT_ZERO(abDomain); 146 RT_ZERO(abNameServers); 147 RT_ZERO(abSearchList); 148 149 regIndex = 0; 150 do { 151 CHAR keyName[256]; 152 DWORD cbKeyName = sizeof(keyName); 153 DWORD keyType = 0; 154 BYTE keyData[1024]; 155 DWORD cbKeyData = sizeof(keyData); 156 157 hrc = RegEnumValueA(m->hKeyTcpipParameters, regIndex, keyName, &cbKeyName, 0, 158 &keyType, keyData, &cbKeyData); 159 if ( hrc == ERROR_SUCCESS 160 || hrc == ERROR_MORE_DATA) 161 { 162 if ( RTStrICmp("Domain", keyName) == 0 163 && cbKeyData > 1 164 && cbKeyData < sizeof(abDomain)) 165 memcpy(abDomain, keyData, cbKeyData); 166 167 else if ( RTStrICmp("DhcpDomain", keyName) == 0 168 && cbKeyData > 1 169 && abDomain[0] == 0 170 && cbKeyData < sizeof(abDomain)) 171 memcpy(abDomain, keyData, cbKeyData); 172 173 else if ( RTStrICmp("NameServer", keyName) == 0 174 && cbKeyData > 1 175 && cbKeyData < sizeof(abNameServers)) 176 memcpy(abNameServers, keyData, cbKeyData); 177 178 else if ( RTStrICmp("DhcpNameServer", keyName) == 0 179 && cbKeyData > 1 180 && abNameServers[0] == 0 181 && cbKeyData < sizeof(abNameServers)) 182 memcpy(abNameServers, keyData, cbKeyData); 183 184 else if ( RTStrICmp("SearchList", keyName) == 0 185 && cbKeyData > 1 186 && cbKeyData < sizeof(abSearchList)) 187 memcpy(abSearchList, keyData, cbKeyData); 188 } 189 regIndex++; 190 } while (hrc != ERROR_NO_MORE_ITEMS); 191 192 /* OK, now parse and update DNS structures. */ 193 /* domain name */ 194 HostDnsInformation info; 195 info.domain = (char*)abDomain; 196 197 /* server list */ 198 strList2List(info.servers, (char *)abNameServers); 199 /* search list */ 200 strList2List(info.searchList, (char *)abSearchList); 201 202 HostDnsMonitor::setInfo(info); 203 204 return S_OK; 205 } 206 207 208 void HostDnsServiceWin::strList2List(std::vector<std::string>& lst, char *strLst) 209 { 210 char *next, *current; 211 char address[512]; 212 213 AssertPtrReturnVoid(strLst); 214 215 if (strlen(strLst) == 0) 216 return; 217 218 current = strLst; 219 do { 220 RT_ZERO(address); 221 next = RTStrStr(current, " "); 222 223 if (next) 224 strncpy(address, current, RT_MIN(sizeof(address)-1, next - current)); 225 else 226 strcpy(address, current); 227 228 lst.push_back(std::string(address)); 229 230 current = next + 1; 231 } while(next); 232 233 }
Note:
See TracChangeset
for help on using the changeset viewer.