VirtualBox

Ignore:
Timestamp:
Oct 27, 2014 12:34:31 PM (10 years ago)
Author:
vboxsync
Message:

Main/HostDnsService: bring back Windows changes of r96331 but with
plain std::string in HostDnsInformation and using explicit Unicode API
and wchar_t when dealing with registry (we always compile with
-DUNICODE, so no need for TCHAR shim). No changes to the original
except minor const correctness tweaks.

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
    218#include <VBox/com/string.h>
    319#include <VBox/com/ptr.h>
    4 
     20#include <VBox/log.h>
    521
    622#include <iprt/assert.h>
     
    1026
    1127#include <string>
     28#include <sstream>
    1229#include <vector>
    1330#include "../HostDnsService.h"
    1431
    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()). */
     36const wchar_t HostDnsServiceWin::pwcKeyRoot[] = L"SYSTEM\\CurrentControlSet\\Services\\Tcpip\\Parameters\\Interfaces";
     37
     38
     39HostDnsServiceWin::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();
    5975}
    6076
     
    6278HostDnsServiceWin::~HostDnsServiceWin()
    6379{
    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
     86bool 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
     110bool 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
     130void 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
     147bool 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
     216bool 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;
    76267}
    77268
     
    82273    AssertComRCReturn(hrc, hrc);
    83274
    84     return updateInfo();
     275    return updateInfo(NULL);
    85276}
    86277
     
    88279void HostDnsServiceWin::monitorThreadShutdown()
    89280{
    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
     286void 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
     299static 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
     309HRESULT 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
     417void 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;
    91422}
    92423
     
    94425int HostDnsServiceWin::monitorWorker()
    95426{
    96     registerNotification(m->hKeyTcpipParameters,
    97                          m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
    98 
    99427    monitorThreadInitializationDone();
    100428
    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
    102439    while (true)
    103440    {
    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,
    109448                        ("WaitForMultipleObjects failed (%d) to wait! Please debug",
    110449                         GetLastError()), VERR_INTERNAL_ERROR);
    111450
    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. */
    123493            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;
    124526        }
    125527        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"));
    133531    return VINF_SUCCESS;
    134532}
    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.

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