1

I have a program that runs on my wife's computer (she lives out of state) which she uses when she is or is not VPN'd into the home computer. The problem that I'm having is that I cannot detect when she has disconnected the VPN and the home computer drive is no longer available. GetLogicalDrives() continues to show the V: drive is available even after she disconnects. The problem is I then call GetFileAttributesEx() which hangs for about 30 seconds so it makes it look like my program is not responding to her.

The following code is basically what I'm using:

    int main()
    {
    #define DRIVE 'V'  // VPN drive
    #define FILE "V:\\Folder\\File.txt"  // file on VPN drive
        WIN32_FILE_ATTRIBUTE_DATA attribute;
        for ( ; ; ) {
            Sleep(10000);  // 10 seconds
    // Check if DRIVE is available
            if (GetLogicalDrives() & (1 << (DRIVE - 'A'))) {
    // Getting here even though VPN has been disconnected
                fprintf(stdout, "Drive %c: is available\n", DRIVE);
    // Now get the attibutes of FILE, but when VPN is disconnected, this
    // hangs for about 30 seconds before returning ERROR_BAD_NETPATH (53)
                if (!GetFileAttributesEx(FILE, GetFileExInfoStandard, &attribute)) {
                    fprintf(stdout, "GetFileAttributesEx() failed, error = %d\n", GetLastError());
                    continue;
                }
                fprintf(stdout, "All is ok\n");
            }
            else fprintf(stdout, "Drive %c: is unavailable\n", DRIVE);
        }
        return 0;
    }

Any suggestions on how to prevent getting hungup for 30 seconds on the GetFileAttributesEx() call after she disconnects her VPN session? I will also need to detect when she reconnects her VPN session.

Codybear
  • 11
  • 1
  • Have you tried this solution https://stackoverflow.com/a/1142185/4603670 – Barmak Shemirani Dec 07 '21 at 04:20
  • 1
    the underlying problem is that windows doesn't know either that the network drive is now unreachable. And when you call `GetFileAttributesEx` windows will try to reconnect the drive and hits a timeout after 30 seconds, after which it'll return to you that it's not reachable. So there's only a few options available: (1) lower the timeout for network drives (2) timeout your `GetFileAttributesEx` call sooner somehow (launch it in a separate thread or call `CancelSyncrhonousIo()`) (3) use another function that allows you to pass an OVERLAPPED structure, then you can use `WaitForSingleObject`. – Turtlefight Dec 07 '21 at 04:33
  • According to [the document](https://learn.microsoft.com/en-us/troubleshoot/windows/win32/win32-networkadapterconfiguration-unable-retrieve-information), .NET Framework `NetworkInterface` class and `GetAdaptersAddresses` API can retrieve network connections correctly. [Here is a NetworkInterface class example.](https://github.com/OJ1978/VPN_Ex) – YangXiaoPo-MSFT Dec 07 '21 at 06:58
  • Windows Explorer chokes on this same scenario so apparently even Microsoft hasn't figured out a good way to deal with it. As others have said, spinning it off to another worker thread is the only workable solution. – Luke Dec 07 '21 at 09:28
  • Thanks for all of the suggestions. Going with a thread that will do the GetLogicalDrives and GetFileAttributesEx and set a global flag if available. There's still the issue when VPN is first disconnected, but within a minute, it'll be all ok. It is unlikely my wife will interact with the program immediately after disconnecting, so I'm not gong to worry about it. It will certainly be a lot more responsive than it was before. Thanks again. – Codybear Dec 07 '21 at 14:13

1 Answers1

0

The NetUseEnum API will tell you if a mapped drive is OK without blocking for ages. You can 'fix' the output of GetLogicalDrives like this:

    auto available_drives = GetLogicalDrives();

    {
        LPUSE_INFO_1 share;
        DWORD read;
        DWORD total;
        auto status =
            NetUseEnum(nullptr, 1, (LPBYTE*)&share, MAX_PREFERRED_LENGTH, &read, &total, nullptr);

        for (auto& s : std::span(share, status == NERR_Success ? read : 0)) {
            if (s.ui1_status != USE_OK && s.ui1_local && s.ui1_local[0] >= L'A' &&
                s.ui1_local[0] <= L'Z' && s.ui1_local[1] == L':')
                available_drives &= ~(1 << (s.ui1_local[0] - L'A'));
        }

        NetApiBufferFree(share);
    }
patstew
  • 1,806
  • 17
  • 21