ping via sockets

S

Sergey V

Hi,

I'm trying to implement ping functionality via nonblocking sockets (as ICMP
protocol sometimes forbidden in firewalls).
Everything works correcly until some amount of pings performed - about 4000
(On WinXP SP2). Connection to valid hosts fails.

Restarting the application does not help. The procedure returns to work only
after some period - if application gets restarted in about 5 minutes.
Looking into TCPView from Sysinternal shows that plenty of open TCP
connection is active.

Runing on Win2000 server, aplication runs without the problems though plenty
of opened TCP connections connections listed too.

Is there way to force TCP connection to close right after the socket is
closed?

Sample code to reproduce:


// socket_ping.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "socket_ping.h"
#include <process.h>
#include <comdef.h>
#include <afxsock.h> // MFC socket extensions
#include <netmon.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

DWORD getHostIP(LPCTSTR pszHost, DWORD* pdwIP/* = NULL*/)
{
// resolve IP address
DWORD dwIP = 0;
HOSTENT* phe;
_bstr_t bsServer(pszHost);

if( pdwIP != NULL )
*pdwIP = 0;
dwIP = inet_addr(bsServer);
if( dwIP == INADDR_NONE ) // already an IP address ?
{
phe = gethostbyname(bsServer);
if( phe == NULL )
{
return 0;
}

dwIP = ((in_addr*)(phe->h_addr_list[0]))->S_un.S_addr;
}
if( pdwIP != NULL )
*pdwIP = dwIP;

return dwIP;
}

BOOL isHostAlive(LPCTSTR pszHost,
int iTimeout = 250,
USHORT uPort = PORT_NETBIOSSSN,
DWORD* pdwIP = NULL )
{
DWORD dwIP = getHostIP(pszHost, pdwIP);

if( dwIP == 0 )
return FALSE;

BOOL bIsAlive;
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in tcpaddr = {AF_INET, htons(uPort)};
int error;
time_t start = time(NULL);
BOOL optTRUE = TRUE, optFALSE = FALSE;
time_t tStart = time(NULL);

tcpaddr.sin_addr.S_un.S_addr = dwIP;
ioctlsocket(s, FIONBIO, (ULONG*)&optTRUE);
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&optTRUE,
sizeof(optTRUE));
setsockopt(s, SOL_SOCKET, SO_DONTLINGER, (char*)&optTRUE,
sizeof(optTRUE));
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optFALSE,
sizeof(optFALSE));
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&optTRUE,
sizeof(optTRUE));

connect(s, (sockaddr*)&tcpaddr, sizeof(tcpaddr));
error = WSAGetLastError();
if( error == 0 || error == WSAEWOULDBLOCK )
{
fd_set fd_write = {1, s};
timeval twait = {0, iTimeout * 1000};

error = select(0, NULL, &fd_write, NULL, &twait);
error = WSAGetLastError();
bIsAlive = FD_ISSET(s, &fd_write);
}
else
{
bIsAlive = (error == WSAECONNREFUSED);
}
shutdown(s, 2 /*SD_BOTH*/);
closesocket(s);

static int n = 0;

printf(_T("%04d: isHostAlive(%s) = %d sec, alive = %d\r\n"),
++n, pszHost, time(NULL) - start, bIsAlive);

return bIsAlive;
}

long cThreads = 0;

static void thread(void* p)
{
for( int i = 1; i < 1000; i++ )
{
isHostAlive(_T("<hostnamehere>"));
}
InterlockedDecrement(&cThreads);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;

// initialize MFC and print and error on failure
if (!AfxWinInit:):GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
return 1;
}

AfxSocketInit();

for( int i = 0; i < 10; i++ )
{
_beginthread(thread, 0, NULL);
InterlockedIncrement(&cThreads);
}

while( cThreads > 0 )
Sleep(100);

return nRetCode;
}
 
A

Arkady Frenkel

The standard way of implementing ping of ICMP or using raw sockets ( you
have ping.c example on Platform SDK ). The lack of raw sockets that it
demand admin rights.
Arkady

Sergey V said:
Hi,

I'm trying to implement ping functionality via nonblocking sockets (as
ICMP protocol sometimes forbidden in firewalls).
Everything works correcly until some amount of pings performed - about
4000 (On WinXP SP2). Connection to valid hosts fails.

Restarting the application does not help. The procedure returns to work
only after some period - if application gets restarted in about 5 minutes.
Looking into TCPView from Sysinternal shows that plenty of open TCP
connection is active.

Runing on Win2000 server, aplication runs without the problems though
plenty of opened TCP connections connections listed too.

Is there way to force TCP connection to close right after the socket is
closed?

Sample code to reproduce:


// socket_ping.cpp : Defines the entry point for the console application.
//

#include "stdafx.h"
#include "socket_ping.h"
#include <process.h>
#include <comdef.h>
#include <afxsock.h> // MFC socket extensions
#include <netmon.h>

#ifdef _DEBUG
#define new DEBUG_NEW
#undef THIS_FILE
static char THIS_FILE[] = __FILE__;
#endif

/////////////////////////////////////////////////////////////////////////////
// The one and only application object

CWinApp theApp;

using namespace std;

DWORD getHostIP(LPCTSTR pszHost, DWORD* pdwIP/* = NULL*/)
{
// resolve IP address
DWORD dwIP = 0;
HOSTENT* phe;
_bstr_t bsServer(pszHost);

if( pdwIP != NULL )
*pdwIP = 0;
dwIP = inet_addr(bsServer);
if( dwIP == INADDR_NONE ) // already an IP address ?
{
phe = gethostbyname(bsServer);
if( phe == NULL )
{
return 0;
}

dwIP = ((in_addr*)(phe->h_addr_list[0]))->S_un.S_addr;
}
if( pdwIP != NULL )
*pdwIP = dwIP;

return dwIP;
}

BOOL isHostAlive(LPCTSTR pszHost,
int iTimeout = 250,
USHORT uPort = PORT_NETBIOSSSN,
DWORD* pdwIP = NULL )
{
DWORD dwIP = getHostIP(pszHost, pdwIP);

if( dwIP == 0 )
return FALSE;

BOOL bIsAlive;
SOCKET s = socket(AF_INET, SOCK_STREAM, 0);
sockaddr_in tcpaddr = {AF_INET, htons(uPort)};
int error;
time_t start = time(NULL);
BOOL optTRUE = TRUE, optFALSE = FALSE;
time_t tStart = time(NULL);

tcpaddr.sin_addr.S_un.S_addr = dwIP;
ioctlsocket(s, FIONBIO, (ULONG*)&optTRUE);
setsockopt(s, SOL_SOCKET, SO_REUSEADDR, (char*)&optTRUE,
sizeof(optTRUE));
setsockopt(s, SOL_SOCKET, SO_DONTLINGER, (char*)&optTRUE,
sizeof(optTRUE));
setsockopt(s, SOL_SOCKET, SO_KEEPALIVE, (char*)&optFALSE,
sizeof(optFALSE));
setsockopt(s, IPPROTO_TCP, TCP_NODELAY, (char*)&optTRUE,
sizeof(optTRUE));

connect(s, (sockaddr*)&tcpaddr, sizeof(tcpaddr));
error = WSAGetLastError();
if( error == 0 || error == WSAEWOULDBLOCK )
{
fd_set fd_write = {1, s};
timeval twait = {0, iTimeout * 1000};

error = select(0, NULL, &fd_write, NULL, &twait);
error = WSAGetLastError();
bIsAlive = FD_ISSET(s, &fd_write);
}
else
{
bIsAlive = (error == WSAECONNREFUSED);
}
shutdown(s, 2 /*SD_BOTH*/);
closesocket(s);

static int n = 0;

printf(_T("%04d: isHostAlive(%s) = %d sec, alive = %d\r\n"),
++n, pszHost, time(NULL) - start, bIsAlive);

return bIsAlive;
}

long cThreads = 0;

static void thread(void* p)
{
for( int i = 1; i < 1000; i++ )
{
isHostAlive(_T("<hostnamehere>"));
}
InterlockedDecrement(&cThreads);
}

int _tmain(int argc, TCHAR* argv[], TCHAR* envp[])
{
int nRetCode = 0;

// initialize MFC and print and error on failure
if (!AfxWinInit:):GetModuleHandle(NULL), NULL, ::GetCommandLine(), 0))
{
// TODO: change error code to suit your needs
cerr << _T("Fatal Error: MFC initialization failed") << endl;
return 1;
}

AfxSocketInit();

for( int i = 0; i < 10; i++ )
{
_beginthread(thread, 0, NULL);
InterlockedIncrement(&cThreads);
}

while( cThreads > 0 )
Sleep(100);

return nRetCode;
}
 
S

Sergey V

As I've mentioned - I know about ICMP ping and somtime it does not work
because of block on ICMP protocol in firewalls.
So if computer fails to be pinged via ICPM, this does not mean computer's
shares are not accessible .
 
A

Alun Jones [MSFT]

The problem in all of this is that there is only one way to tell if a
resource is accessible, and that is to try and access the resource.

To tell if a share is accessible, you need to access the share. Since the
computer may be locked down against responding to _any_ other request,
nothing will confirm for certain that the share is inaccessible other than
attempting to access the share, and being refused.

Ping is great for debugging network troubles, when ICMP and/or UDP
(depending on the version of 'ping') are allowed.

As to your code, perhaps it would help if you did the following:

1. Check (and handle) errors every time a function fails.
2. Don't call WSAGetLastError() / GetLastError() unless a function fails.

These are important debugging steps that you should master very early on in
Windows development.

Take special note of item 2 - a function may succeed, but the error value
that GetLastError() exposes to you may be set. A simple example of how this
might happen is to imagine a "file exists" function that opens the file and
returns true or false on the basis of whether that open works or not. The
open will fail, but the "file exists" function will succeed.

GetLastError() only has meaning immediately after a function has failed,
after a function has succeeded, that value has no defined purpose.

Alun.
~~~~
 
H

Herb Martin

Sergey V said:
As I've mentioned - I know about ICMP ping and somtime it does not work
because of block on ICMP protocol in firewalls.
So if computer fails to be pinged via ICPM, this does not mean computer's
shares are not accessible .

No, not if you suspect or know of a blocking firewall,
or if the machine itself has such a firewall or has otherwise
disabled echo (ping) responses.

Ping (when it works) prives that routing is working. It
never proves that any particular protocol or service is
reasonable/not-reachable except ping (ICMP echo) itself.

It does give a good idea if the network is working in those
cases where you know the network and firewall design.

Other (similar) tests can be performed based on Telnet (TCP
only), or based on NetCat (nc.exe) for both UDP and TPC
protocals in most cases.
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Top