VirtualBox

Ignore:
Timestamp:
Sep 30, 2014 2:45:00 PM (10 years ago)
Author:
vboxsync
Message:

Main: DnsMonitorService: step on unicode rails: store network configuration in unicode-compatible containner (std::wstring) (preliminary tested on Linux, Mac and Windows); DnsMonitorService for Windows: reworked in order to subscribe to correct events and filter-out those ones we don't interested in. (Experimantal, needs more testing and review).

File:
1 edited

Legend:

Unmodified
Added
Removed
  • trunk/src/VBox/Main/src-server/win/HostDnsServiceWin.cpp

    r50263 r52897  
    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 TCHAR HostDnsServiceWin::m_pwcKeyRoot[] = _T("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(const_cast<TCHAR *>(m_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(TCHAR *wcsPath, TCHAR *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 = RegOpenKeyEx(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        _tcscpy(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 = RegOpenKeyEx(HKEY_LOCAL_MACHINE, m_pwcKeyRoot, 0, KEY_READ, &hTmpKey);
     225    if (rc == ERROR_SUCCESS)
     226    {
     227        /* Get info about amount of available network interfaces. */
     228        rc = RegQueryInfoKey(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                TCHAR sSubKeyName[VBOX_KEY_NAME_LEN_MAX];
     237                for (DWORD idxSubKey = 0; idxSubKey < cSubKeys; idxSubKey++)
     238                {
     239                    rc = RegEnumKey(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                        TCHAR sSubKeyFullPath[VBOX_KEY_NAME_LEN_MAX];
     244                        RT_ZERO(sSubKeyFullPath);
     245                        _tcscpy(sSubKeyFullPath, m_pwcKeyRoot);
     246                        rc  = _tcscat_s(sSubKeyFullPath, VBOX_KEY_NAME_LEN_MAX, _T("\\"));
     247                        rc |= _tcscat_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::wstring>& pVectorToExtend, std::wstring &wcsParameter)
     287{
     288    std::wstringstream   wcsStream(wcsParameter);
     289    std::wstring         wcsSubString;
     290
     291    while (std::getline(wcsStream, wcsSubString, _T(' ')))
     292        pVectorToExtend.push_back(wcsSubString);
     293}
     294
     295
     296#ifdef DEBUG
     297static void hostDnsWinDumpList(std::vector<std::wstring>& awcszValues)
     298{
     299    for (int idxItem = 0; idxItem < awcszValues.size(); idxItem++)
     300    {
     301        LogRel(("%ls\n", awcszValues[idxItem].data()));
     302    }
     303}
     304#endif /* DEBUG */
     305
     306
     307HRESULT HostDnsServiceWin::updateInfo(uint8_t *fWhatsChanged)
     308{
     309    HostDnsInformation pHostDnsInfo;
     310    RT_ZERO(pHostDnsInfo);
     311
     312    /* Any interfaces available? */
     313    if (m_aWarehouse.size() > VBOX_OFFSET_SUBTREE_EVENTS)
     314    {
     315        /* Walk across all the available interfaces and collect network configuration data:
     316         * domain name, name servers and search list. */
     317        for (int idxKey = VBOX_OFFSET_SUBTREE_EVENTS; idxKey < m_aWarehouse.size(); idxKey++)
     318        {
     319            LONG rc;
     320
     321            /* Get number of key values. */
     322            DWORD cValues = 0;
     323            rc = RegQueryInfoKey(m_aWarehouse[idxKey].hKey, NULL, NULL, NULL, NULL, NULL, NULL, &cValues, NULL, NULL, NULL, NULL);
     324            if (rc == ERROR_SUCCESS)
     325            {
     326                for (DWORD idxValue = 0; idxValue < cValues; idxValue++)
     327                {
     328                    TCHAR wcsValueName[VBOX_KEY_NAME_LEN_MAX];
     329                    DWORD cbValueName = VBOX_KEY_NAME_LEN_MAX;
     330                    TCHAR wcsData[VBOX_KEY_NAME_LEN_MAX];
     331                    DWORD cbData = VBOX_KEY_NAME_LEN_MAX;
     332
     333                    /* Walk across all the properties of given interface. */
     334                    rc = RegEnumValue(m_aWarehouse[idxKey].hKey, idxValue, wcsValueName, &cbValueName, 0, NULL, (LPBYTE)wcsData, &cbData);
     335                    if (rc == ERROR_SUCCESS)
     336                    {
     337                       
     338                        if ((   _tcscmp(wcsValueName, _T("Domain")) == 0
     339                             || _tcscmp(wcsValueName, _T("DhcpDomain")) == 0)
     340                            && _tcslen(wcsData) > 0)
     341                        {
     342                            /* We rely on that fact that Windows host cannot be a member of more than one domain in the same time! */
     343                            if (pHostDnsInfo.domain.empty())
     344                                pHostDnsInfo.domain = std::wstring(wcsData);
     345                        }
     346                        else if ((   _tcscmp(wcsValueName, _T("NameServer")) == 0
     347                                  || _tcscmp(wcsValueName, _T("DhcpNameServer")) == 0)
     348                                 && _tcslen(wcsData) > 0)
     349                        {
     350                            extendVectorWithStrings(pHostDnsInfo.servers, std::wstring(wcsData));
     351                        }
     352                        else if (_tcscmp(wcsValueName, _T("SearchList")) == 0
     353                                 && _tcslen(wcsData) > 0)
     354                        {
     355                            extendVectorWithStrings(pHostDnsInfo.searchList, std::wstring(wcsData));
     356                        }
     357                    }
     358                }
     359            }
     360        }
     361   
     362        uint8_t fChanged = VBOX_EVENT_NO_CHANGES;
     363        /* Compare cached network settings and newly obtained ones. */
     364        if (pHostDnsInfo.servers != m_hostInfoCache.servers)
     365        {
     366#ifdef DEBUG
     367            LogRel(("Servers changed from:\n"));
     368            hostDnsWinDumpList(m_hostInfoCache.servers);
     369            LogRel(("to:\n"));
     370            hostDnsWinDumpList(pHostDnsInfo.servers);
     371#endif /* DEBUG */
     372            fChanged |= VBOX_EVENT_SERVERS_CHANGED;
     373        }
     374       
     375        if (pHostDnsInfo.domain != m_hostInfoCache.domain)
     376        {
     377#ifdef DEBUG
     378            LogRel(("Domain changed: [%ls]->[%ls].\n",
     379                m_hostInfoCache.domain.empty() ? _T("NONE") : (const unsigned short *)m_hostInfoCache.domain.data(),
     380                pHostDnsInfo.domain.data()));
     381#endif /* DEBUG */
     382            fChanged |= VBOX_EVENT_DOMAIN_CHANGED;
     383        }
     384       
     385        if (pHostDnsInfo.searchList != m_hostInfoCache.searchList)
     386        {
     387#ifdef DEBUG
     388            LogRel(("SearchList changed from:\n"));
     389            hostDnsWinDumpList(m_hostInfoCache.searchList);
     390            LogRel(("to:\n"));
     391            hostDnsWinDumpList(pHostDnsInfo.searchList);
     392#endif /* DEBUG */
     393            fChanged |= VBOX_EVENT_SEARCHLIST_CHANGED;
     394        }
     395       
     396        /* Provide info about changes if requested. */
     397        if (fWhatsChanged)
     398            *fWhatsChanged = fChanged;
     399
     400        /* Update host network configuration cache. */
     401        m_hostInfoCache.servers.clear();
     402        m_hostInfoCache.servers = pHostDnsInfo.servers;
     403        m_hostInfoCache.domain.clear();
     404        m_hostInfoCache.domain.assign(pHostDnsInfo.domain);
     405        m_hostInfoCache.searchList.clear();
     406        m_hostInfoCache.searchList = pHostDnsInfo.searchList;
     407
     408        HostDnsMonitor::setInfo(pHostDnsInfo);
     409    }
     410
     411    return S_OK;
     412}
     413
     414
     415void HostDnsServiceWin::getEventHandles(HANDLE *ahEvents)
     416{
     417    AssertReturnVoid(m_aWarehouse.size() > 0);
     418    for (int idxHandle = 0; idxHandle < m_aWarehouse.size(); idxHandle++)
     419        ahEvents[idxHandle] = m_aWarehouse[idxHandle].hEvent;
    91420}
    92421
     
    94423int HostDnsServiceWin::monitorWorker()
    95424{
    96     registerNotification(m->hKeyTcpipParameters,
    97                          m->haDataEvent[DATA_DNS_UPDATE_EVENT]);
    98 
    99425    monitorThreadInitializationDone();
    100426
    101     DWORD dwRc;
     427    uint8_t fWhatsChabged = VBOX_EVENT_NO_CHANGES;
     428
     429    if (!m_fInitialized)
     430    {
     431        LogRel(("Host DNS monitor was not initialized properly.\n"));
     432        return VERR_INTERNAL_ERROR;
     433    }
     434
     435    HANDLE  ahEvents[MAXIMUM_WAIT_OBJECTS];
     436
    102437    while (true)
    103438    {
    104         dwRc = WaitForMultipleObjects(DATA_MAX_EVENT,
    105                                       m->haDataEvent,
    106                                       FALSE,
    107                                       INFINITE);
    108         AssertMsgReturn(dwRc != WAIT_FAILED,
     439        /* Each new iteration we need to update event handles list we monitor. */
     440        RT_ZERO(ahEvents);
     441        getEventHandles(ahEvents);
     442
     443        DWORD rc = WaitForMultipleObjects((DWORD)m_aWarehouse.size(), ahEvents, FALSE, INFINITE);
     444
     445        AssertMsgReturn(rc != WAIT_FAILED,
    109446                        ("WaitForMultipleObjects failed (%d) to wait! Please debug",
    110447                         GetLastError()), VERR_INTERNAL_ERROR);
    111448
    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         {
     449        /* Shutdown requested. */
     450        if      (rc == (WAIT_OBJECT_0 + VBOX_OFFSET_SHUTDOWN_EVENT)) break;
     451        /* Interfaces amount changed. */
     452        else if (rc == (WAIT_OBJECT_0 + VBOX_OFFSET_TREE_EVENT))
     453        {
     454            Log2(("Network interfaces amount changed.\n"));
     455
     456            /* Drop interface events. */
     457            if (dropSubTreeNotifications())
     458            {
     459                /* Drop event which is corresponds to interfaces tree changes. */
     460                if (releaseWarehouseItem(VBOX_OFFSET_TREE_EVENT))
     461                {
     462                    /* Restart interface tree monitoring. */
     463                    if (subscribeTo(const_cast<TCHAR *>(m_pwcKeyRoot), NULL, REG_NOTIFY_CHANGE_NAME))
     464                    {
     465                        /* Restart interface events. */
     466                        if (enumerateSubTree())
     467                        {
     468                            Log2(("Monitor restarted successfully.\n"));
     469                            fWhatsChabged = VBOX_EVENT_NO_CHANGES;
     470                            updateInfo(&fWhatsChabged);
     471                            if (fWhatsChabged & VBOX_EVENT_SERVERS_CHANGED)
     472                            {
     473                                LogRel(("Notification sent (1).\n"));
     474                                notifyAll();
     475                            }
     476                            continue;
     477                        }
     478                        else
     479                            LogRel(("Monitor unstable: failed to subscribe network configuration changes.\n"));
     480                    }
     481                    else
     482                        LogRel(("Monitor unstable: failed to subscribe interface changes.\n"));
     483                }
     484                else
     485                    LogRel(("Monitor unstable: failed to unsubscribe from interfaces amount changes.\n"));
     486            }
     487            else
     488                LogRel(("Monitor unstable: failed to unsubscribe from previous notifications.\n"));
     489           
     490            /* If something went wrong, we break monitoring. */
    123491            break;
     492
     493        }
     494        /* DNS update events range. */
     495        else if (rc > (WAIT_OBJECT_0 + VBOX_OFFSET_SUBTREE_EVENTS) &&
     496                 rc < (WAIT_OBJECT_0 + m_aWarehouse.size() - VBOX_OFFSET_SUBTREE_EVENTS))
     497        {
     498            Log2(("Network setting has changed at interface %ls.\n", m_aWarehouse[rc - WAIT_OBJECT_0].wcsInterface));
     499           
     500            /* Drop previous notifications first. */
     501            if (dropSubTreeNotifications())
     502            {
     503                /* Re-subscribe. */
     504                if (enumerateSubTree())
     505                {
     506                    Log2(("Restart monitoring.\n"));
     507                    fWhatsChabged = VBOX_EVENT_NO_CHANGES;
     508                    updateInfo(&fWhatsChabged);
     509                    if (fWhatsChabged & VBOX_EVENT_SERVERS_CHANGED)
     510                    {
     511                        LogRel(("Notification sent (2).\n"));
     512                        notifyAll();
     513                    }
     514                    continue;
     515                }
     516                else
     517                    LogRel(("WARNING: Monitor unstable: unable to re-subscribe to notifications.\n"));
     518            }
     519            else
     520                LogRel(("WARNING: Monitor unstable: failed to unsubscribe from previous notifications.\n"));
     521
     522            /* If something went wrong, we stop monitoring. */
     523            break;
    124524        }
    125525        else
    126         {
    127             AssertMsgFailedReturn(
    128               ("WaitForMultipleObjects returns out of bound index %d. Please debug!",
    129                                    dwRc),
    130               VERR_INTERNAL_ERROR);
    131         }
    132     }
     526            AssertMsgFailedReturn(("WaitForMultipleObjects returns out of bound (%d) index %d. Please debug!", m_aWarehouse.size(), rc), VERR_INTERNAL_ERROR);
     527    }
     528    LogRel(("Monitor thread exited.\n"));
    133529    return VINF_SUCCESS;
    134530}
    135531
    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