Thread: Network Status

  1. #1
    Registered User
    Join Date
    Aug 2003
    Posts
    288

    Network Status

    Im not sure if this is meant to be in the networking section, if so, sorry.
    It uses the win api and its more of a windows question in general anyway.

    Im trying to find out the status of all computers connected on my LAN, i want to find out if they are online/offline and if online, i want to find out if they are logged in (if possible).

    So far, i managed to find some code that lists all computer names on a network, and using this list, i used somewhat of a hack to check if they were online/offline (pinging them and hiding the command prompt).

    Code:
    void NetworkStatus()
    {
    	//vars
    
    	do
    	{
    		pbuf = NULL;
    		statusNetAPI = NetServerEnum(NULL, 101, &pbuf, 25600, &entriesread, &totalentries, SV_TYPE_ALL, NULL, &resume);
    
    		if ((statusNetAPI == NERR_Success || statusNetAPI == ERROR_MORE_DATA) && pbuf != NULL)
    		{
    			pSI = (SERVER_INFO_101 *)pbuf;
    
    			for (i = 0; i < entriesread; ++i)
    			{
    				sprintf(sBuffer, "%S: ", pSI[i].sv101_name);
    				strcat(sReturn, sBuffer);
    
    				sprintf(sBuffer, "ping %S -n 1 -w 100", nBegin);
    				nStart = GetTickCount();
    
    				LoadProgram(sBuffer); //just loads 'sBuffer' and hides the window (async)
    
    				if (GetTickCount() - nStart >= 50)
    					//Offline
    				else
    					//Online
    			}
    		}
    
    		if (pbuf != NULL)
    			NetApiBufferFree(pbuf);
    	}
    	while (statusNetAPI == ERROR_MORE_DATA);
    }
    but the problem is, this code takes about 100 ms per computer, and i got around 30 computers on my LAN.. if im lucky, it takes 3 seconds, but usually, it takes anywhere between 1 to 10 minutes.. also, its not that accurate, sometimes it returns offline for a computer thats definately online.

  2. #2
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    What happens if you comment out the LoadProgram call? This should give you an idea whether the culprit is NetServerEnum or LoadProgram. Could you cache the computer list? You could look into IcmpSendEcho or IcmpSendEcho2 to replace the ping call. These take an IP address so you would have to use gethostbyname first. Does this network have a domain controller and is the code running on it?

    >> its not that accurate, sometimes it returns offline for a computer thats definately online. <<

    If a few threads are active and/or code or data needs to be loaded from the disk the ping call could easily take more than 50ms.

  3. #3
    Registered User
    Join Date
    Aug 2003
    Posts
    288
    i dont think it has a domain controller, and im just running it from 1 of the clients.. netserverenum isnt the issue at the moment, its the ping, im looking into icmpSendEcho(2) now. thanks for the advice

    edit:

    is pinging the only way to check if a computer is online/offline? because the ping timeout is kinda slow, and if i set it too low, its inaccurate

  4. #4
    Yes, my avatar is stolen anonytmouse's Avatar
    Join Date
    Dec 2002
    Posts
    2,544
    You can use IcmpSendEcho2 to send out all your ping requests at the same time. Here is a sample demonstrating IcmpSendEcho2:
    Code:
    #include <winsock2.h>
    #include <windows.h>
    #include <Ipexport.h>
    #include <icmpapi.h>
    #include <stdio.h>
    
    #if defined(_MSC_VER)
    #pragma comment(lib, "Iphlpapi.lib")
    #pragma comment(lib, "Ws2_32.lib")
    #endif
    
    /*
     * Simple structure of arrays to create Targets collection.
     */
    #define MAX_TARGETS 300
    struct
    {
    	struct in_addr IPAddresses[MAX_TARGETS];
    	BYTE           Buffers    [MAX_TARGETS][sizeof(ICMP_ECHO_REPLY) + 32];
    	HANDLE         Events     [MAX_TARGETS];
    	UINT           cTargets;
    } Targets;
    
    /*
     * Add an IP address to the Targets collection.
     */
    BOOL new_Target(LPCSTR szIPAddress)
    {
    	if (Targets.cTargets < MAX_TARGETS)
    	{
    		Targets.Events[Targets.cTargets] = CreateEvent(NULL, FALSE, FALSE, NULL);
    		Targets.IPAddresses[Targets.cTargets].S_un.S_addr = inet_addr(szIPAddress);
    		Targets.cTargets++;
    
    		return TRUE;
    	}
    
    	return FALSE;
    }
    
    /*
     * There appears to be a problem with the import lib for IcmpParseReplies
     * so we load it at run-time.
     */
    DWORD wrapIcmpParseReplies(LPVOID ReplyBuffer, DWORD ReplySize)
    {
    	typedef (WINAPI * pIPR)(LPVOID, DWORD);
    	static pIPR dl_IcmpParseReplies;
    
    	if (!dl_IcmpParseReplies)
    	{
    		HMODULE hICMP = LoadLibrary(TEXT("ICMP.dll"));
    		dl_IcmpParseReplies = (pIPR) GetProcAddress(hICMP, "IcmpParseReplies");
    	}
    
    	if (dl_IcmpParseReplies)
    		return dl_IcmpParseReplies(ReplyBuffer, ReplySize);
    	else
    		return 0;
    }
    
    /*
     * main function.
     */
    int main(void)
    {
    	size_t i;
    	DWORD  ret;
    	HANDLE hIcmp;
    	BYTE   PingData[16];
    
    	/* Add IP Addresses to check. */
    	new_Target( "66.139.79.229" );
    	new_Target( "192.168.0.1"   );
    	new_Target( "192.168.0.2"   );
    	new_Target( "192.168.0.17"  );
    	new_Target( "10.0.0.1"      );
    	new_Target( "10.0.0.2"      );
    
    	/* You can also check your entire subnet with something like: */
    	for (i = 1;i < 256;i++)
    	{
    		char buf[50];
    		sprintf(buf, "192.168.0.%d", i);
    		new_Target(buf);
    	}
    
    	hIcmp = IcmpCreateFile();
    
    	/* Send out all our async ping requests. Timeout is 250ms. Change if needed. */
    	for (i = 0; i < Targets.cTargets; i++)
    	{
    		IcmpSendEcho2(hIcmp, Targets.Events[i], NULL, 0,
    		               Targets.IPAddresses[i].S_un.S_addr, PingData, sizeof(PingData), 
    		               NULL, Targets.Buffers[i], sizeof(Targets.Buffers[i]), 250);
    	}
    
    	/* Wait for all our ping requests to return or timeout. */
    	WaitForMultipleObjects(Targets.cTargets, Targets.Events, TRUE, 2500);
    
    	/* Check the results. */
    	for (i = 0; i < Targets.cTargets; i++)
    	{
    		ret = wrapIcmpParseReplies(Targets.Buffers[i], sizeof(Targets.Buffers[i]));
    		printf("%s:  %s\n", ret != 0 ? "UP  " : "DOWN", inet_ntoa(Targets.IPAddresses[i]));
    	}
    
    	IcmpCloseHandle(hIcmp);
    
    	getchar();
    	return 0;
    }
    Notes:
    - I successfully used this code to check my subnet. Run-time was under a second.
    - If you have slower paths in your network (WAN, VPN, etc) you may need to increase the timeout.
    - Smart network components (routers, switches, etc) may detect this as a DOS attack and reject the ping packets.
    - Error checking and cleanup code is incomplete.
    - You may find it faster to get rid of NetServerEnum. You could ping the entire subnet and then lookup names with gethostbyaddr.
    Last edited by anonytmouse; 05-12-2005 at 02:43 AM.

  5. #5
    Registered User
    Join Date
    Aug 2003
    Posts
    288
    that works perfectly, thanks again anonytmouse

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Troubles with Sockets
    By cornholio in forum Windows Programming
    Replies: 6
    Last Post: 10-26-2005, 05:31 AM
  2. Need help with easy Network setup
    By the dead tree in forum Tech Board
    Replies: 9
    Last Post: 04-08-2005, 07:44 PM
  3. Binary Search Trees Part III
    By Prelude in forum A Brief History of Cprogramming.com
    Replies: 16
    Last Post: 10-02-2004, 03:00 PM
  4. Network status
    By mduarte in forum Networking/Device Communication
    Replies: 1
    Last Post: 01-19-2004, 11:40 AM
  5. Determining status of a network connection?
    By Cat in forum Windows Programming
    Replies: 0
    Last Post: 06-04-2003, 05:30 PM