VirtualBox

Changeset 53159 in vbox


Ignore:
Timestamp:
Oct 28, 2014 2:51:59 PM (11 years ago)
Author:
vboxsync
svn:sync-xref-src-repo-rev:
96695
Message:

Main/HostDnsService: revert windows code back to r91891. The rewrite
in r96327 is wrong. I can't seem to find any paper trail for what was
the problem with the original code, but at least it monitors the right
place in the registry.

Location:
trunk/src/VBox/Main/src-server
Files:
2 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/HostDnsService.h

    r53151 r53159  
    146146# endif
    147147# ifdef RT_OS_WINDOWS
    148 /* Maximum size of Windows registry key (according to MSDN). */
    149 #define VBOX_KEY_NAME_LEN_MAX   (255)
    150 
    151148class HostDnsServiceWin : public HostDnsMonitor
    152149{
    153 public:
     150    public:
    154151    HostDnsServiceWin();
    155152    ~HostDnsServiceWin();
    156 
    157153    HRESULT init();
    158154
    159 protected:
     155    protected:
    160156    virtual void monitorThreadShutdown();
    161157    virtual int monitorWorker();
    162158
    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;
    238166};
    239167# 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; -*- */
    182#include <VBox/com/string.h>
    193#include <VBox/com/ptr.h>
    20 #include <VBox/log.h>
     4
    215
    226#include <iprt/assert.h>
     
    2610
    2711#include <string>
    28 #include <sstream>
    2912#include <vector>
    3013#include "../HostDnsService.h"
    3114
    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))
     15struct 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
     25static 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
     39HostDnsServiceWin::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
     62HostDnsServiceWin::~HostDnsServiceWin()
     63{
     64    if (m && !m->hKeyTcpipParameters)
    4965    {
    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;
    6975    }
    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();
    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 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;
    26776}
    26877
     
    27382    AssertComRCReturn(hrc, hrc);
    27483
    275     return updateInfo(NULL);
     84    return updateInfo();
    27685}
    27786
     
    27988void HostDnsServiceWin::monitorThreadShutdown()
    28089{
    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]);
    42291}
    42392
     
    42594int HostDnsServiceWin::monitorWorker()
    42695{
     96    registerNotification(m->hKeyTcpipParameters,
     97                         m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
     98
    42799    monitorThreadInitializationDone();
    428100
    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;
    439102    while (true)
    440103    {
    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,
    448109                        ("WaitForMultipleObjects failed (%d) to wait! Please debug",
    449110                         GetLastError()), VERR_INTERNAL_ERROR);
    450111
    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        {
    493123            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                 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;
    526124        }
    527125        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        }
    529132    }
    530     LogRel(("Monitor thread exited.\n"));
    531133    return VINF_SUCCESS;
    532134}
     135
     136
     137HRESULT 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
     208void 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.

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