Solved

C: Is computer reachable

Posted on 2004-09-21
38
801 Views
Last Modified: 2012-06-27
Hello experts,
I'm looking for a solution in pure C (Windows APIs are needed?) to verify if a computer is reachable or not.
I'm using Visual Studio 6.

If anyone knows how to do this
please supply an appropriate snippet.

Thank you for any help.

   HStrix

0
Comment
Question by:HStrix
[X]
Welcome to Experts Exchange

Add your voice to the tech community where 5M+ people just like you are talking about what matters.

  • Help others & share knowledge
  • Earn cash & points
  • Learn & ask questions
  • 19
  • 12
  • 6
  • +1
38 Comments
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12112172
You can use Winsock functions: gethostbyname and gethostbyaddr:
http://msdn.microsoft.com/library/en-us/winsock/winsock/gethostbyname_2.asp
http://msdn.microsoft.com/library/en-us/winsock/winsock/gethostbyaddr_2.asp

also you can make a ping to know if computer is available in real-time.
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12112239
Also, take a look to this article about pinging in Windows:
http://www.codeproject.com/internet/winping.asp
0
 

Author Comment

by:HStrix
ID: 12112663
Thank you jaime_olivares,
I found the following code (at http://msdn.microsoft.com/library/en-us/winsock/winsock/gethostbyname_2.asp):
---
      // Declare and initialize variables
      hostent* remoteHost;
      char* host_name;
      unsigned int addr;
      //----------------------
      // User inputs name of host
      //printf("Input name of host: ");                                
      host_name = (char*) malloc(sizeof(char*)*16);
      //fgets(host_name, 16, stdin);                              /7  <= original code
      host_name = "mycomputername";                       // <== this doesn't work ??
---
Can you help me to replace that statement?
0
Independent Software Vendors: We Want Your Opinion

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12112797
Just need this:

     hostent* remoteHost;
     char* host_name;
     unsigned int addr;
     host_name = "mycomputername";
     // now you can call your function      
0
 

Author Comment

by:HStrix
ID: 12112937
OK, after this my code is:
---
      // If the user input is an alpha name for the host, use gethostbyname()
      // If not, get host by addr (assume IPv4)
      //if (isalpha(host_name[0])) {   /* host address is a name */
      //host_name[strlen(host_name)-1] = '\0'; /* NULL TERMINATED */
      remoteHost = gethostbyname(host_name);
      //}
      //else  {
      //addr = inet_addr(host_name);
      //remoteHost = gethostbyaddr((char *)&addr, 4, AF_INET);
      //}

                int intLastErr = WSAGetLastError(); // gives 10093

      if (WSAGetLastError() != 0) {
      if (WSAGetLastError() == 11001)
      //printf("Host not found...\nExiting.\n");
            strcpy(strComputerVerify,"Host not found");
      }
      else
      //printf("error#:%ld\n", WSAGetLastError());
            strcpy(strComputerVerify,"unknown error");
---
I get in remotehost as address all zeros.
WSAGetLastError = 10093
Can you help me again?
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12113010
You have commented the most important line:
addr = inet_addr(host_name);
0
 

Author Comment

by:HStrix
ID: 12113062
Now my code looks as follows:
---
      // If the user input is an alpha name for the host, use gethostbyname()
      // If not, get host by addr (assume IPv4)
      //if (isalpha(host_name[0])) {   /* host address is a name */
      //host_name[strlen(host_name)-1] = '\0'; /* NULL TERMINATED */
      //remoteHost = gethostbyname(host_name);
      //}
      //else  {
      addr = inet_addr(host_name);
      remoteHost = gethostbyaddr((char *)&addr, 4, AF_INET);  // remoteHost is again zero
      //}
      int intLastErr = WSAGetLastError(); // 10093 appears again
      //if (WSAGetLastError() != 0) {
      if (intLastErr != 0)
      {
            //if (WSAGetLastError() == 11001)
            if (intLastErr == 11001)
            {
                  //printf("Host not found...\nExiting.\n");
                  strcpy(strComputerVerify,"Host not found");
            } else
            {
                  strcpy(strComputerVerify,"???");
            }
      }
      else
            //printf("error#:%ld\n", WSAGetLastError());
            strcpy(strComputerVerify,"unknown error")
---
Something is not working...
0
 
LVL 86

Expert Comment

by:jkr
ID: 12113149
'gethostbyname()' will not help you in determining if a machine is reachable. It just tells whether there's a DNS record available or not. You could just use

WKSTA_INFO_100 w100;

NetWkstaGetInfo ( L"\\\\themachine", 100, &w100);

If that call fails, the machine is not reachable.
0
 

Author Comment

by:HStrix
ID: 12113263
Thank you jkr,
what .h file and which .lib file do I need?
I added netapi32.lib, but I miss something.
0
 
LVL 86

Expert Comment

by:jkr
ID: 12113349
The header file is 'lmwksta.h' - BTW, NOTE that this might also fail if theat machine is not running windows or the Workstation service is not running (the latter meaning "unreachable" anyway). However, a machine can also be cofigured to not answer to "pings".
0
 

Author Comment

by:HStrix
ID: 12113478
OK,
now I get the error
---
error C2664: 'NetWkstaGetInfo': cannot convert parameter 1 from 'const unsigned short[11]' to 'LPSTR'
---
My code is:
---
void verifyComputer(void)
{
   WKSTA_INFO_100 w100;
   NetWkstaGetInfo ( L"\\\\mycomputername", 100, &w100);
}
---
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12113518
>NOTE that this might also fail if theat machine is not running windows or the >Workstation service is not running (the latter meaning "unreachable" anyway).
That's why ping is a better solution

> However, a machine can also be cofigured to not answer to "pings".
In case machines are yours, then there is no such problem
0
 

Author Comment

by:HStrix
ID: 12113637
Concerning the machine:
I know that the machine I'm trying to verify does exist.
But I'm not sure that it is running.
In addition the caller might have made a typo (the access in made via a .bat file).
0
 
LVL 86

Expert Comment

by:jkr
ID: 12113646
>>error C2664: 'NetWkstaGetInfo': cannot convert parameter 1 from 'const unsigned short[11]' to
>>'LPSTR'

Are you on Win9x? Then use

void verifyComputer(void)
{
  WKSTA_INFO_100 w100;
  NetWkstaGetInfo ( _T("\\\\mycomputername"), 100, &w100);
}

0
 
LVL 86

Expert Comment

by:jkr
ID: 12113655
>>In case machines are yours, then there is no such problem

And no problem about the WkStaSvc.
0
 
LVL 55

Expert Comment

by:Jaime Olivares
ID: 12113737
Notices there are many considerations when using NetWkstaGetInfo, depending on Operating System and security rights. Read more at:
http://msdn.microsoft.com/library/default.asp?url=/library/en-us/netmgmt/netmgmt/netwkstagetinfo.asp
0
 

Author Comment

by:HStrix
ID: 12113774
I'm in Win2000 Workstation.
0
 

Author Comment

by:HStrix
ID: 12113802
But it is not an MFC application,
it is a console application, it starts with
---
int APIENTRY WinMain(HINSTANCE hInstance,
                     HINSTANCE hPrevInstance,
                     LPSTR        lpCmdLine,
                     int             nCmdShow )
{

    ......

}
0
 
LVL 86

Expert Comment

by:jkr
ID: 12113913
>> Notices there are many considerations when using NetWkstaGetInfo, depending on Operating
>>System

The idea is that
a) All users can use infolevel 100
b) If the call is successful, the machine is available.

>> I'm in Win2000 Workstation.

The following compiles just fine:

#include <windows.h>
#include <lm.h>
#include <lmwksta.h>
#include <tchar.h>

#pragma comment ( lib, "netapi32.lib")

void verifyComputer(void)
{
 WKSTA_INFO_100* pw100;
 NetWkstaGetInfo ( _T("\\\\mycomputername"), 100, (LPBYTE*) &pw100);

 NetApiBufferFree ( pw100);
}

int APIENTRY WinMain(HINSTANCE hInstance,
                    HINSTANCE hPrevInstance,
                    LPSTR        lpCmdLine,
                    int             nCmdShow )
{

   return 0;

}

0
 
LVL 22

Expert Comment

by:grg99
ID: 12114036
You need to clarify a few details:

What do you mean by "reachable"?

Some possibilities:

(1)  The DNS name exists

(2)  That IP address responds to "ping".

(3) Some port accepts connections:  Which one? Could be Telnet, www, FTP, Gopher, IRC, DNS, SMB.

----------------

Note that a lot of computers are behind firewalls, or have ping turned off, specifically to avoid other computers figuring out they are there.

Perhaps if you'd explain exactly what you're trying to do we could suggest something appropriate.

0
 

Author Comment

by:HStrix
ID: 12114219
Thanks, now I modified the code to
---
void verifyComputer(void)
{
      DWORD netret;
      LPTSTR pszServerName = NULL;
      pszServerName = (char *)L"\\\\mycomputername"; // result is "\" only
      pszServerName = _T("\\\\mycomputername");        // result is "\\mycomputername"
      WKSTA_INFO_100* pw100;
      //netret = NetWkstaGetInfo ( pszServerName, 100, (LPBYTE *)&pw100);
                netret = NetWkstaGetInfo ( _T("\\\\mhpab5gc"), 100, (LPBYTE *)&pw100);  // it leads to the same result
      if( netret == NERR_Success )  // netret = 53
      {
            strcpy(strComputerVerify,"Host is available");
      } else
      {
            strcpy(strComputerVerify,"Host not found");
      }
      NetApiBufferFree ( pw100);
}
---
It compiles error free, but the execution gives code 53.

If I use
--
pszServerName = (char *)L"\\\\mycomputername"; // result is "\" only
//netret = NetWkstaGetInfo ( pszServerName, 100, (LPBYTE *)&pw100);
---
then I get netret=0, but is this OK for the contents of pszServerName?

For testing I use the computername I'm running on,
so I'm sure that it is OK.

If I use
--
pszServerName = (char *)L"\\\\mycomputernameX"; // result is "\" only but "mycomputernameX" is unknown
//netret = NetWkstaGetInfo ( pszServerName, 100, (LPBYTE *)&pw100);
---
then I get netret=53.

0
 
LVL 86

Expert Comment

by:jkr
ID: 12114310
>>pszServerName = (char *)L"\\\\mycomputernameX"; // result is "\" only but "mycomputernameX" i

That cannot work (thus the ERROR_BAD_NETPATH). It needs to be UNICODE:

void verifyComputer(char* pszName)
{
WKSTA_INFO_100* pw100;
wchar_t awcName [ MAX_COMPUTERNAME_LENGTH + 1];

wsprintf ( awcName, "%S", pszNme);

NetWkstaGetInfo ( awcName, 100, (LPBYTE*) &pw100);

NetApiBufferFree ( pw100);
}
0
 

Author Comment

by:HStrix
ID: 12114329
Here is some more explanation:

The C[++] I'm writing is designed to invoke another program (using ShellExecute)
and then stops working.

The another program is located on a share.
Now I want to check step-by-step
 - of the computer is reachable,
 - then if the share is still available
 - and at last if the program I want to activate is on that share.
And in each case I want to inform the user about the cause of an occured problem.

Everything is already working, if the three checks above are not required.
But I thought, there might be some circumstances, that problems occur.
0
 
LVL 86

Expert Comment

by:jkr
ID: 12114377
>>Now I want to check step-by-step
>>- of the computer is reachable,
>>- then if the share is still available

Then, the next step is using 'NetShareGetInfo()'...

>> - and at last if the program I want to activate is on that share.

... followed by 'NetShareAdd()'.

0
 

Author Comment

by:HStrix
ID: 12114453
Yes, I wanted to ask appropriate questions in that order.
0
 

Author Comment

by:HStrix
ID: 12114556
For the code
---
void verifyComputer(char* pszName)
{
      DWORD netret;
      WKSTA_INFO_100* pw100;
      wchar_t awcName [ MAX_COMPUTERNAME_LENGTH + 1];
 // error C2664: 'wsprintfA': cannot convert parameter 1 from 'const unsigned short[11]' to 'LPSTR'                    occurs for next line:
      wsprintf ( awcName, "%S", pszName);
// error C2664: 'NetWkstaGetInfo': cannot convert parameter 1 from 'const unsigned short[11]' to 'LPSTR'           occurs for next line:            
      NetWkstaGetInfo ( awcName, 100, (LPBYTE*) &pw100);
---
I get above's errors.

I call the routine as follows
---
char *computername = "";
computername= token; // as it is in =>http://www.experts-exchange.com/Programming/Programming_Languages/Cplusplus/Q_21137583.html
verifyComputer(computername);
---
0
 
LVL 86

Expert Comment

by:jkr
ID: 12114597
>> // error C2664: 'wsprintfA':

Ouch :o) - that should be 'wsprintfW()'

Try

#include <windows.h>
#ifndef UNICODE
#define UNICODE
#include <lm.h>
#include <lmwksta.h>
#undef UNICODE
#endif

#pragma comment ( lib, "netapi32.lib")

void verifyComputer(char* pszName)
{
WKSTA_INFO_100* pw100;
wchar_t awcName [ MAX_COMPUTERNAME_LENGTH + 1];

wsprintfW ( awcName, L"%S", pszName);

NetWkstaGetInfo ( awcName, 100, (LPBYTE*) &pw100);

NetApiBufferFree ( pw100);
}
0
 

Author Comment

by:HStrix
ID: 12114696
Still I get the following:
---
     WKSTA_INFO_100* pw100;
     wchar_t awcName [ MAX_COMPUTERNAME_LENGTH + 1];
     wsprintfW ( awcName, L"%S", pszName);
// error C2664: 'NetWkstaGetInfo': cannot convert parameter 1 from 'const unsigned short[11]' to 'LPSTR'           occurs for next line:            
     NetWkstaGetInfo ( awcName, 100, (LPBYTE*) &pw100);
---
0
 

Author Comment

by:HStrix
ID: 12115051
I changed
   NetWkstaGetInfo ( awcName, 100, (LPBYTE*) &pw100);
to
  netret = NetWkstaGetInfo ( (LPSTR) &awcName, 100, (LPBYTE*) &pw100);
then I get netret=0.
But I'm confused is this OK or not?
0
 
LVL 86

Expert Comment

by:jkr
ID: 12115132
'0' is

#define NERR_Success            0       /* Success */

But something is fishy here - could you look up the declaration of 'NetWkstaGetInfo()' in your header file?
0
 

Author Comment

by:HStrix
ID: 12116183
OK, I'll check that tomorrow.
On my computer is the environment of .Net 2003 and of the Platform SDK.
0
 

Author Comment

by:HStrix
ID: 12119967
Here it is:
---
excerpt from lmwksta.h
---
//
// Function Prototypes
//

NET_API_STATUS NET_API_FUNCTION
NetWkstaGetInfo (
    IN  LMSTR   servername OPTIONAL,
    IN  DWORD   level,
    OUT LPBYTE  *bufptr
    );

NET_API_STATUS NET_API_FUNCTION
NetWkstaSetInfo (
    IN  LMSTR   servername OPTIONAL,
    IN  DWORD   level,
    IN  LPBYTE  buffer,
    OUT LPDWORD parm_err OPTIONAL
    );

NET_API_STATUS NET_API_FUNCTION
NetWkstaUserGetInfo (
    IN  LMSTR  reserved,
    IN  DWORD   level,
    OUT LPBYTE  *bufptr
    );

NET_API_STATUS NET_API_FUNCTION
NetWkstaUserSetInfo (
    IN  LMSTR  reserved,
    IN  DWORD   level,
    OUT LPBYTE  buf,
    OUT LPDWORD parm_err OPTIONAL
    );

NET_API_STATUS NET_API_FUNCTION
NetWkstaUserEnum (
    IN  LMSTR       servername OPTIONAL,
    IN  DWORD       level,
    OUT LPBYTE      *bufptr,
    IN  DWORD       prefmaxlen,
    OUT LPDWORD     entriesread,
    OUT LPDWORD     totalentries,
    IN  OUT LPDWORD resumehandle OPTIONAL
    );
---
0
 
LVL 86

Expert Comment

by:jkr
ID: 12124250
Hmm, the part of interest now would be the typedef for 'LMSTR'...
0
 

Author Comment

by:HStrix
ID: 12124487
Here it is:
---
excerpt from lmcons.h
---
//
// Only the UNICODE version of the LM APIs are available on NT.
// Non-UNICODE version on other platforms
//
#if defined( _WIN32_WINNT ) || defined( WINNT ) || defined( __midl ) \
    || defined( FORCE_UNICODE )
#define LMSTR   LPWSTR
#define LMCSTR  LPCWSTR
#else
#define LMSTR   LPSTR
#define LMCSTR  LPCSTR
#endif
---
0
 
LVL 86

Accepted Solution

by:
jkr earned 500 total points
ID: 12124626
Ah, here we have it :o)

Then, that should be

Try

#include <windows.h>
#define FORCE_UNICODE
#include <lm.h>
#include <lmwksta.h>

#pragma comment ( lib, "netapi32.lib")

void verifyComputer(char* pszName)
{
WKSTA_INFO_100* pw100;
wchar_t awcName [ MAX_COMPUTERNAME_LENGTH + 1];

wsprintfW ( awcName, L"%S", pszName);

NetWkstaGetInfo ( awcName, 100, (LPBYTE*) &pw100);

NetApiBufferFree ( pw100);
}

Actually, _WIN32_WINNT or WINNT  should be defined somewhere, though...
0
 

Author Comment

by:HStrix
ID: 12124648
and follow up ...

excerpt from mapinls.h (appears first in the dropdownlist referring to definition)
---
typedef CHAR FAR *                                    LPSTR;
---

excerpt from winnt.h (appears secondly in the dropdownlist)
---
typedef CHAR *LPSTR, *PSTR;
---
0
 

Author Comment

by:HStrix
ID: 12124800
I tested it and it works as expected.
To get this solution some very special know-how seems to be required.
But as you know this was not your first help for me.

Thank you jkr very much for your great help!

    HStrix
0
 
LVL 86

Expert Comment

by:jkr
ID: 12124980
>>To get this solution some very special know-how seems to be required.

Actually, some experience with MS' poorly doumented network APIs helps also :o)

Great that it finally worked.
0

Featured Post

Industry Leaders: We Want Your Opinion!

We value your feedback.

Take our survey and automatically be enter to win anyone of the following:
Yeti Cooler, Amazon eGift Card, and Movie eGift Card!

Question has a verified solution.

If you are experiencing a similar issue, please ask a related question

Preface I don't like visual development tools that are supposed to write a program for me. Even if it is Xcode and I can use Interface Builder. Yes, it is a perfect tool and has helped me a lot, mainly, in the beginning, when my programs were small…
This tutorial is posted by Aaron Wojnowski, administrator at SDKExpert.net.  To view more iPhone tutorials, visit www.sdkexpert.net. This is a very simple tutorial on finding the user's current location easily. In this tutorial, you will learn ho…
The goal of this video is to provide viewers with basic examples to understand recursion in the C programming language.
Video by: Grant
The goal of this video is to provide viewers with basic examples to understand and use while-loops in the C programming language.

749 members asked questions and received personalized solutions in the past 7 days.

Join the community of 500,000 technology professionals and ask your questions.

Join & Ask a Question