Changeset 53151 in vbox for trunk/src/VBox/Main/src-server/win
- Timestamp:
- Oct 27, 2014 12:34:31 PM (10 years ago)
- File:
-
- 1 edited
Legend:
- Unmodified
- Added
- Removed
-
trunk/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp
r53122 r53151 1 /* -*- indent-tabs-mode: nil; -*- */ 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 2 18 #include <VBox/com/string.h> 3 19 #include <VBox/com/ptr.h> 4 20 #include <VBox/log.h> 5 21 6 22 #include <iprt/assert.h> … … 10 26 11 27 #include <string> 28 #include <sstream> 12 29 #include <vector> 13 30 #include "../HostDnsService.h" 14 31 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())); 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)) 49 { 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")); 69 } 70 else 71 /* 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(); 59 75 } 60 76 … … 62 78 HostDnsServiceWin::~HostDnsServiceWin() 63 79 { 64 if (m && !m->hKeyTcpipParameters) 65 { 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; 75 } 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 here 90 * (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 case 164 * 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 else 182 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 to 203 * 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 and 233 * 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 else 252 LogRel(("Unable to open interfaces list (1).\n")); 253 } 254 RegCloseKey(hTmpKey); 255 return true; 256 } 257 else 258 LogRel(("Unable to open interfaces list (2).\n")); 259 } 260 else 261 LogRel(("Unable to open interfaces list (3).\n")); 262 RegCloseKey(hTmpKey); 263 } 264 else 265 LogRel(("Unable to open interfaces list (4).\n")); 266 return false; 76 267 } 77 268 … … 82 273 AssertComRCReturn(hrc, hrc); 83 274 84 return updateInfo( );275 return updateInfo(NULL); 85 276 } 86 277 … … 88 279 void HostDnsServiceWin::monitorThreadShutdown() 89 280 { 90 SetEvent(m->haDataEvent[DATA_SHUTDOWN_EVENT]); 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; 91 422 } 92 423 … … 94 425 int HostDnsServiceWin::monitorWorker() 95 426 { 96 registerNotification(m->hKeyTcpipParameters,97 m->haDataEvent[DATA_DNS_UPDATE_EVENT]);98 99 427 monitorThreadInitializationDone(); 100 428 101 DWORD dwRc; 429 uint8_t fWhatsChabged = 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 102 439 while (true) 103 440 { 104 dwRc = WaitForMultipleObjects(DATA_MAX_EVENT, 105 m->haDataEvent, 106 FALSE, 107 INFINITE); 108 AssertMsgReturn(dwRc != WAIT_FAILED, 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, 109 448 ("WaitForMultipleObjects failed (%d) to wait! Please debug", 110 449 GetLastError()), VERR_INTERNAL_ERROR); 111 450 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 { 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 fWhatsChabged = VBOX_EVENT_NO_CHANGES; 472 updateInfo(&fWhatsChabged); 473 if (fWhatsChabged & 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. */ 123 493 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 fWhatsChabged = VBOX_EVENT_NO_CHANGES; 510 updateInfo(&fWhatsChabged); 511 if (fWhatsChabged & VBOX_EVENT_SERVERS_CHANGED) 512 { 513 LogRel(("Notification sent (2).\n")); 514 notifyAll(); 515 } 516 continue; 517 } 518 else 519 LogRel(("WARNING: Monitor unstable: unable to re-subscribe to notifications.\n")); 520 } 521 else 522 LogRel(("WARNING: Monitor unstable: failed to unsubscribe from previous notifications.\n")); 523 524 /* If something went wrong, we stop monitoring. */ 525 break; 124 526 } 125 527 else 126 { 127 AssertMsgFailedReturn( 128 ("WaitForMultipleObjects returns out of bound index %d. Please debug!", 129 dwRc), 130 VERR_INTERNAL_ERROR); 131 } 132 } 528 AssertMsgFailedReturn(("WaitForMultipleObjects returns out of bound (%d) index %d. Please debug!\n", m_aWarehouse.size(), rc), VERR_INTERNAL_ERROR); 529 } 530 LogRel(("Monitor thread exited.\n")); 133 531 return VINF_SUCCESS; 134 532 } 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_SUCCESS160 || hrc == ERROR_MORE_DATA)161 {162 if ( RTStrICmp("Domain", keyName) == 0163 && cbKeyData > 1164 && cbKeyData < sizeof(abDomain))165 memcpy(abDomain, keyData, cbKeyData);166 167 else if ( RTStrICmp("DhcpDomain", keyName) == 0168 && cbKeyData > 1169 && abDomain[0] == 0170 && cbKeyData < sizeof(abDomain))171 memcpy(abDomain, keyData, cbKeyData);172 173 else if ( RTStrICmp("NameServer", keyName) == 0174 && cbKeyData > 1175 && cbKeyData < sizeof(abNameServers))176 memcpy(abNameServers, keyData, cbKeyData);177 178 else if ( RTStrICmp("DhcpNameServer", keyName) == 0179 && cbKeyData > 1180 && abNameServers[0] == 0181 && cbKeyData < sizeof(abNameServers))182 memcpy(abNameServers, keyData, cbKeyData);183 184 else if ( RTStrICmp("SearchList", keyName) == 0185 && cbKeyData > 1186 && 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 else226 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.