Intel® Fortran Compiler
Build applications that can scale for the future with optimized code designed for Intel® Xeon® and compatible processors.
28383 Discussions

Check internet connection from Fortran program

SoniaG
Novice
1,632 Views

I want my Fortran program to check for internet connection and warn the user if not connected.  I think I need to use the method GetConnectivity but can't find an example of this for use in Fortran. Apparently the API, InternetGetConnectedState is no longer recommended.

Any help or advice would be appreciated - manys thanks in advance.

0 Kudos
1 Solution
FortranFan
Honored Contributor II
1,517 Views

@SoniaG ,

Re: ".. I think I need to use the method GetConnectivity but can't find an example of this for use in Fortran. ..," you may have seen this at the Microsoft site:

https://docs.microsoft.com/en-us/windows/win32/api/netlistmgr/nf-netlistmgr-inetworklistmanager-getconnectivity

You'll notice the GetConnectivity - which is indeed Microsoft's recommended method in their so-called unmanaged programs (and which is what all Fortran apps are) on Windows - is a C++ class method of INetworkListManager that is invokable via COM.  As such, you would either need to use Intel Fortran's COM interoperability module(s) or setup something yourself using C-Fortran interoperability.  Both are a little more effort than I would be willing to undertake, so I would instead write a small extern "C" wrapper function in C++ like so: it's a one-time effort easier to manage I feel:

 

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Netlistmgr.h>
#include <atlbase.h>

extern "C" int IsConnected(char *msg, size_t lenmsg) 
{ 

  int irc = 0;
  CoInitialize(NULL);
  {
    CComPtr<INetworkListManager> pNLM;
    HRESULT hr = CoCreateInstance(CLSID_NetworkListManager, NULL, 
      CLSCTX_ALL, __uuidof(INetworkListManager), (LPVOID*)&pNLM);
    if (SUCCEEDED(hr))
    {
      NLM_CONNECTIVITY con = NLM_CONNECTIVITY_DISCONNECTED;
      hr = pNLM->GetConnectivity(&con);
      if SUCCEEDED(hr)
      {
        if (con & NLM_CONNECTIVITY_DISCONNECTED)
          snprintf(msg, lenmsg, "%s\n", "Disconnected");
        if (con & NLM_CONNECTIVITY_IPV4_NOTRAFFIC)
          snprintf(msg, lenmsg, "%s\n", "IP4: No Traffic");
        if (con & NLM_CONNECTIVITY_IPV6_NOTRAFFIC)
          snprintf(msg, lenmsg, "%s\n", "IP6: No Traffic");
        if (con & NLM_CONNECTIVITY_IPV4_INTERNET)
          snprintf(msg, lenmsg, "%s\n", "IP4: Internet");
        if (con & NLM_CONNECTIVITY_IPV4_LOCALNETWORK)
          snprintf(msg, lenmsg, "%s\n", "IP4: Local");
        if (con & NLM_CONNECTIVITY_IPV4_SUBNET)
          snprintf(msg, lenmsg, "%s\n", "IP4: Subnet");
        if (con & NLM_CONNECTIVITY_IPV6_INTERNET)
          snprintf(msg, lenmsg, "%s\n", "IP6: Internet");
        if (con & NLM_CONNECTIVITY_IPV6_LOCALNETWORK)
          snprintf(msg, lenmsg, "%s\n", "IP6: Local");
        if (con & NLM_CONNECTIVITY_IPV6_SUBNET)
          snprintf(msg, lenmsg, "%s\n", "IP6: Subnet");
      }
    }
    irc = (int)hr;
  }
  CoUninitialize();
  return irc; 
} 

 

And setup an interface to it in Fortran like so, again a one-time effort:

 

module NetListMgr_m

   use, intrinsic :: iso_c_binding, only : c_char, c_int, c_size_t

   interface
      function IsConnected( Msg, LenMsg ) result(r) bind(C, name="IsConnected" )

      ! int IsConnected(char *msg, size_t lenmsg);

         import :: c_char, c_int, c_size_t

         ! Argument list
         character(kind=c_char, len=1), intent(in) :: Msg(*)
         integer(c_size_t), intent(in), value      :: LenMsg
         ! Function result
         integer(c_int) :: r

      end function 
   end interface

end module

 

Then the following Fortran test program can make use of it:

 

program TestConnection

   use, intrinsic :: iso_c_binding, only : c_char, c_size_t, c_int
   use NetListMgr_m, only : IsConnected
   
   character(kind=c_char, len=256) :: ConnectionState
   integer(c_size_t) :: lens
   integer(c_int) :: cstat

   lens = int( len(ConnectionState), kind=kind(lens) )
   cstat = IsConnected( ConnectionState, lens )
   print *, "ctsat: ", cstat
   print *, trim(ConnectionState)
   
end program 

 

You can tuck away the above C function and the Fortran module code in a library (static or DLL) and use it in your Fortran programs - Visual Studio projects can make this easy as you may know.

From the command-line, for illustration purposes, you can expect the following behavior:

 

C:\Temp>cl /c /EHsc /W3 IsConnected.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.26.28806 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

IsConnected.cpp

C:\Temp>ifort /c /standard-semantics /warn:all /stand:f18 NetListMgr.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1.2 Build 20201208_000000
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.


C:\Temp>ifort /c /standard-semantics /warn:all /stand:f18 TestConnection.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1.2 Build 20201208_000000
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.


C:\Temp>link TestConnection.obj NetListMgr.obj IsConnected.obj /subsystem:console /out:TestConnection.exe
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.


C:\Temp>TestConnection.exe
 ctsat:  0
 IP4: Internet



C:\Temp>

 

P.S.> Some of the above code is a bit more verbose than otherwise, but it's for the benefit of other readers also.  Also, it's possible Intel Fortran provides some module procedures for this - I've not checked - but that will be compiler-specific.  The above should work with any Fortran standard supporting compiler.

 

View solution in original post

7 Replies
andrew_4619
Honored Contributor II
1,607 Views

Not quite the same thing but I use URLDownloadToFile to download a page from the web to a local file. A failure to get something that is known to exist could be indicative of no connection.  

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,596 Views

Experiment with EXECUTE_COMMAND_LINE with "ping -w 500 -n 1 yahoo.com>check.txt"

You should test to see if exitstat returns error code when ping fails, and in which case you need not check the check.txt for ping error.

Jim Dempsey

0 Kudos
JohnNichols
Valued Contributor III
1,588 Views
0 Kudos
SoniaG
Novice
1,557 Views

Thanks @jimdempseyatthecove 

I have written the following code but, although the command execution runs, I almost always get an estat of 1.  My program is running in Windows and I am connected to the internet (it's a strong signal and not intermittant).  I get similar results whether running in debug (Visual Studio) or in production.

If the code below looks ok, I assume there must be something else at play?

call execute_command_line("ping -w 500 -n 1 yahoo.com>check.txt",exitstat=estat,cmdstat=cstat,cmdmsg=cmsg)
if(cstat > 0) then
  iret = messagebox(ghwndmain,'Command execution failed with error'//trim(cmsg)//char(0),'Check for                    internet connection'//char(0),mb_ok)
else if(cstat < 0) then
  iret = messagebox(ghwndmain,'Command execution not supported'//trim(cmsg)//char(0),'Check for                      internet connection'//char(0),mb_ok)
 else
    write(cestat,'(I4)')estat
    if(estat==0)then
      iret = messagebox(ghwndmain,'Internet connection ok, estat ='//trim(cestat)//char(0),'Check for                                internet connection'//char(0),mb_ok)
    else
      iret = messagebox(ghwndmain,'No internet connection found, estat ='//trim(cestat)//char(0),'Check                        for internet connection'//char(0),mb_ok)
     end if
end if

0 Kudos
jimdempseyatthecove
Honored Contributor III
1,537 Views

What happens if you set the timeout to -w 5000?

Jim Dempsey

0 Kudos
FortranFan
Honored Contributor II
1,518 Views

@SoniaG ,

Re: ".. I think I need to use the method GetConnectivity but can't find an example of this for use in Fortran. ..," you may have seen this at the Microsoft site:

https://docs.microsoft.com/en-us/windows/win32/api/netlistmgr/nf-netlistmgr-inetworklistmanager-getconnectivity

You'll notice the GetConnectivity - which is indeed Microsoft's recommended method in their so-called unmanaged programs (and which is what all Fortran apps are) on Windows - is a C++ class method of INetworkListManager that is invokable via COM.  As such, you would either need to use Intel Fortran's COM interoperability module(s) or setup something yourself using C-Fortran interoperability.  Both are a little more effort than I would be willing to undertake, so I would instead write a small extern "C" wrapper function in C++ like so: it's a one-time effort easier to manage I feel:

 

#include <stdio.h>
#include <tchar.h>
#include <Windows.h>
#include <Netlistmgr.h>
#include <atlbase.h>

extern "C" int IsConnected(char *msg, size_t lenmsg) 
{ 

  int irc = 0;
  CoInitialize(NULL);
  {
    CComPtr<INetworkListManager> pNLM;
    HRESULT hr = CoCreateInstance(CLSID_NetworkListManager, NULL, 
      CLSCTX_ALL, __uuidof(INetworkListManager), (LPVOID*)&pNLM);
    if (SUCCEEDED(hr))
    {
      NLM_CONNECTIVITY con = NLM_CONNECTIVITY_DISCONNECTED;
      hr = pNLM->GetConnectivity(&con);
      if SUCCEEDED(hr)
      {
        if (con & NLM_CONNECTIVITY_DISCONNECTED)
          snprintf(msg, lenmsg, "%s\n", "Disconnected");
        if (con & NLM_CONNECTIVITY_IPV4_NOTRAFFIC)
          snprintf(msg, lenmsg, "%s\n", "IP4: No Traffic");
        if (con & NLM_CONNECTIVITY_IPV6_NOTRAFFIC)
          snprintf(msg, lenmsg, "%s\n", "IP6: No Traffic");
        if (con & NLM_CONNECTIVITY_IPV4_INTERNET)
          snprintf(msg, lenmsg, "%s\n", "IP4: Internet");
        if (con & NLM_CONNECTIVITY_IPV4_LOCALNETWORK)
          snprintf(msg, lenmsg, "%s\n", "IP4: Local");
        if (con & NLM_CONNECTIVITY_IPV4_SUBNET)
          snprintf(msg, lenmsg, "%s\n", "IP4: Subnet");
        if (con & NLM_CONNECTIVITY_IPV6_INTERNET)
          snprintf(msg, lenmsg, "%s\n", "IP6: Internet");
        if (con & NLM_CONNECTIVITY_IPV6_LOCALNETWORK)
          snprintf(msg, lenmsg, "%s\n", "IP6: Local");
        if (con & NLM_CONNECTIVITY_IPV6_SUBNET)
          snprintf(msg, lenmsg, "%s\n", "IP6: Subnet");
      }
    }
    irc = (int)hr;
  }
  CoUninitialize();
  return irc; 
} 

 

And setup an interface to it in Fortran like so, again a one-time effort:

 

module NetListMgr_m

   use, intrinsic :: iso_c_binding, only : c_char, c_int, c_size_t

   interface
      function IsConnected( Msg, LenMsg ) result(r) bind(C, name="IsConnected" )

      ! int IsConnected(char *msg, size_t lenmsg);

         import :: c_char, c_int, c_size_t

         ! Argument list
         character(kind=c_char, len=1), intent(in) :: Msg(*)
         integer(c_size_t), intent(in), value      :: LenMsg
         ! Function result
         integer(c_int) :: r

      end function 
   end interface

end module

 

Then the following Fortran test program can make use of it:

 

program TestConnection

   use, intrinsic :: iso_c_binding, only : c_char, c_size_t, c_int
   use NetListMgr_m, only : IsConnected
   
   character(kind=c_char, len=256) :: ConnectionState
   integer(c_size_t) :: lens
   integer(c_int) :: cstat

   lens = int( len(ConnectionState), kind=kind(lens) )
   cstat = IsConnected( ConnectionState, lens )
   print *, "ctsat: ", cstat
   print *, trim(ConnectionState)
   
end program 

 

You can tuck away the above C function and the Fortran module code in a library (static or DLL) and use it in your Fortran programs - Visual Studio projects can make this easy as you may know.

From the command-line, for illustration purposes, you can expect the following behavior:

 

C:\Temp>cl /c /EHsc /W3 IsConnected.cpp
Microsoft (R) C/C++ Optimizing Compiler Version 19.26.28806 for x64
Copyright (C) Microsoft Corporation.  All rights reserved.

IsConnected.cpp

C:\Temp>ifort /c /standard-semantics /warn:all /stand:f18 NetListMgr.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1.2 Build 20201208_000000
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.


C:\Temp>ifort /c /standard-semantics /warn:all /stand:f18 TestConnection.f90
Intel(R) Fortran Intel(R) 64 Compiler Classic for applications running on Intel(R) 64, Version 2021.1.2 Build 20201208_000000
Copyright (C) 1985-2020 Intel Corporation.  All rights reserved.


C:\Temp>link TestConnection.obj NetListMgr.obj IsConnected.obj /subsystem:console /out:TestConnection.exe
Microsoft (R) Incremental Linker Version 14.26.28806.0
Copyright (C) Microsoft Corporation.  All rights reserved.


C:\Temp>TestConnection.exe
 ctsat:  0
 IP4: Internet



C:\Temp>

 

P.S.> Some of the above code is a bit more verbose than otherwise, but it's for the benefit of other readers also.  Also, it's possible Intel Fortran provides some module procedures for this - I've not checked - but that will be compiler-specific.  The above should work with any Fortran standard supporting compiler.

 

JohnNichols
Valued Contributor III
1,510 Views

Sonia:

FortranFan's method is as good as it gets, I would adopt this one and stop searching.  

0 Kudos
Reply