Ping from C tutorial, problem

  • Follow


I have taken Jacob's code verbatum from "advanced.pdf".  It compiles fine 
but when run, I get this error.

"The ping.exe file is linked to missing export ws2_32.dll:getnameinfo."

On checking out ws2_32.dll in wordpad, ws2_32.dll does not contain any 
referance to "getnameinfo".  

This is on win98, I also tried the ping.exe on an nt4 box with the same 
error poping up.

Any idars anyone.

Thank Richard

0
Reply Richard 9/23/2005 3:16:52 AM

On Fri, 23 Sep 2005 03:16:52 GMT, Richard Sanders
<richard@stardate.ca> wrote:

>I have taken Jacob's code verbatum from "advanced.pdf".  It compiles fine 
>but when run, I get this error.
>
>"The ping.exe file is linked to missing export ws2_32.dll:getnameinfo."
>
>On checking out ws2_32.dll in wordpad, ws2_32.dll does not contain any 
>referance to "getnameinfo".  

Checking MSDN library, "getnameinfo" gets no hits at all.  It is not
the name of any API that I can see.

>This is on win98, I also tried the ping.exe on an nt4 box with the same 
>error poping up.
>
>Any idars anyone.
Ask Jacob what the correct API call is. :-)

>
>Thank Richard

-- 
ArarghMail509 at [drop the 'http://www.' from ->] http://www.arargh.com
BCET Basic Compiler Page: http://www.arargh.com/basic/index.html

To reply by email, remove the garbage from the reply address.
0
Reply ararghmail509NOSPAM 9/23/2005 3:33:53 AM


Richard Sanders wrote:

> I have taken Jacob's code verbatum from "advanced.pdf".  It compiles fine 
> but when run, I get this error.
> 
> "The ping.exe file is linked to missing export ws2_32.dll:getnameinfo."
> 
> On checking out ws2_32.dll in wordpad, ws2_32.dll does not contain any 
> referance to "getnameinfo".  
> 
> This is on win98, I also tried the ping.exe on an nt4 box with the same 
> error poping up.
> 
> Any idars anyone.
> 
> Thank Richard
> 
Sorry Richard but the ping.exe I have here uses from ws2_32.dll
   WS2_32.DLL
   OrigFirstThunk:  0000B0EC (Unbound IAT)
   TimeDateStamp:   00000000 -> Thu Jan 01 01:00:00 1970
   ForwarderChain:  00000000
   First thunk RVA: 0000B1B8
   Ordn  Name
     99  WSACleanup
     13  inet_ntoa
     14  inet_addr
     26  gethostbyname
      3  setsockopt
      4  sendto
     49  WSAStartup
     51  WSASocketA
     62  WSARecvFrom
     86  WSAGetOverlappedResult
     87  WSAGetLastError
     96  WSACreateEvent

I just do not know where you get that...
0
Reply jacob 9/23/2005 10:06:59 AM

In article <4333d3c1$0$1733$8fcfb975@news.wanadoo.fr>, 
jacob@jacob.remcomp.fr says...
> Richard Sanders wrote:
> 
> > I have taken Jacob's code verbatum from "advanced.pdf".  It compiles fine 
> > but when run, I get this error.
> > 
> > "The ping.exe file is linked to missing export ws2_32.dll:getnameinfo."
> > 
> > On checking out ws2_32.dll in wordpad, ws2_32.dll does not contain any 
> > referance to "getnameinfo".  
> > 
> > This is on win98, I also tried the ping.exe on an nt4 box with the same 
> > error poping up.
> > 
> > Any idars anyone.
> > 
> > Thank Richard
> > 
> Sorry Richard but the ping.exe I have here uses from ws2_32.dll
>    WS2_32.DLL
>    OrigFirstThunk:  0000B0EC (Unbound IAT)
>    TimeDateStamp:   00000000 -> Thu Jan 01 01:00:00 1970
>    ForwarderChain:  00000000
>    First thunk RVA: 0000B1B8
>    Ordn  Name
>      99  WSACleanup
>      13  inet_ntoa
>      14  inet_addr
>      26  gethostbyname
>       3  setsockopt
>       4  sendto
>      49  WSAStartup
>      51  WSASocketA
>      62  WSARecvFrom
>      86  WSAGetOverlappedResult
>      87  WSAGetLastError
>      96  WSACreateEvent
> 
> I just do not know where you get that...
> 

Hi Jacob
  I did a search for files containing text "getnameinfo" on the lib 
directory of LCC and "getnameinfo" is in ws2_32.lib and netutils.lib.

I guess that one or both the libs expect ws2_32.dll to contain the 
function.

Cheers Richard
0
Reply Richard 9/24/2005 1:12:49 AM

Yes, you are right. From the MSDN docs I read gather that
getnameinfo is a replacement for the gethosbyaddr function.
The gethostname will NOT run under windows 98.

Windows 98 is obsoleted by Microsoft and no longer updated.

Your choices are:

1) Get a newer ws2_32.dll ( maybe from an XP system) and
see if it works

2) Upgrade your system to XP (recommended)

3) Use the source code below. Replace the call of getnameinfo
   below by gethostbyaddr. This is not trivial since the
   return value of the calling function should be changed.

Here is the source code of the ping utility:

----------------------------------------------------------cut here
#include <winsock2.h>
#include <ws2tcpip.h>
#include <stdio.h>
#include <stdlib.h>
#include <ping.h>

#include "iphdr.h"

#define DEFAULT_DATA_SIZE      32       // default data size
#define DEFAULT_SEND_COUNT     4        // number of ICMP requests to send
#define DEFAULT_RECV_TIMEOUT   6000     // six second
#define DEFAULT_TTL            128
#define MAX_RECV_BUF_LEN       0xFFFF   // Max incoming packet size.

static int   gAddressFamily=AF_UNSPEC,         // Address family to use
       gProtocol=IPPROTO_ICMP,           // Protocol value
       gTtl=DEFAULT_TTL;                 // Default TTL value
static int   gDataSize=DEFAULT_DATA_SIZE;      // Amount of data to send
static char *gDestination,                // Destination
       recvbuf[MAX_RECV_BUF_LEN];        // For received packets
static int   recvbuflen = MAX_RECV_BUF_LEN;    // Length of received 
packets.
static int verbose;
//
// Function: InitIcmpHeader
//
// Description:
//    Helper function to fill in various stuff in our ICMP request.
//
static void InitIcmpHeader(char *buf, int datasize)
{
     ICMP_HDR   *icmp_hdr=NULL;
     char       *datapart=NULL;

     icmp_hdr = (ICMP_HDR *)buf;
     icmp_hdr->icmp_type     = ICMPV4_ECHO_REQUEST_TYPE;        // 
request an ICMP echo
     icmp_hdr->icmp_code     = ICMPV4_ECHO_REQUEST_CODE;
     icmp_hdr->icmp_id       = (USHORT)GetCurrentProcessId();
     icmp_hdr->icmp_checksum = 0;
     icmp_hdr->icmp_sequence = 0;

     datapart = buf + sizeof(ICMP_HDR);
     //
     // Place some data in the buffer.
     //
     memset(datapart, 'A', datasize);
}

//
// Function: checksum
//
// Description:
//    This function calculates the 16-bit one's complement sum
//    of the supplied buffer (ICMP) header.
//
static USHORT checksum(USHORT *buffer, int size)
{
     unsigned long cksum=0;

     while (size > 1)
     {
         cksum += *buffer++;
         size -= sizeof(USHORT);
     }
     if (size)
     {
         cksum += *(UCHAR*)buffer;
     }
     cksum = (cksum >> 16) + (cksum & 0xffff);
     cksum += (cksum >>16);
     return (USHORT)(~cksum);
}

//
// Function: ValidateArgs
//
// Description:
//    Parse the command line arguments.
//
static void ReadArgs(PingInterface *params)
{
     gDestination = params->HostName;
	if (params->ttl)
		gTtl = params->ttl;
	if (params->DataSize)
     	gDataSize = params->DataSize;
	if (params->TotalPackets <= 0)
		params->TotalPackets = DEFAULT_SEND_COUNT;
	params->TotalPackets++;
	if (params->SleepTime <= 0)
		params->SleepTime = 1000;
	verbose  = params->verbose ? 1 : 0;
	params->MaxTime = -1;
	params->MinTime = 10000000;
}

//
// Function: SetIcmpSequence
//
// Description:
//    This routine sets the sequence number of the ICMP request packet.
//
static int SetIcmpSequence(char *buf)
{
     static ULONG    sequence = 1;
     ICMP_HDR    *icmpv4= (ICMP_HDR *)buf;

     icmpv4->icmp_sequence = (USHORT)sequence++;
	return icmpv4->icmp_sequence;
}

//
// Function: ComputeIcmpChecksum
//
// Description:
//    This routine computes the checksum for the ICMP request. For IPv4 its
//    easy, just compute the checksum for the ICMP packet and data. For 
IPv6,
//    its more complicated. The pseudo checksum has to be computed for IPv6
//    which includes the ICMP6 packet and data plus portions of the IPv6
//    header which is difficult since we aren't building our own IPv6
//    header.
//
static void ComputeIcmpChecksum(SOCKET s, char *buf, int packetlen, 
struct addrinfo *dest)
{
     if (gAddressFamily == AF_INET)
     {
         ICMP_HDR    *icmpv4=NULL;

         icmpv4 = (ICMP_HDR *)buf;
         icmpv4->icmp_checksum = 0;
         icmpv4->icmp_checksum = checksum((USHORT *)buf, packetlen);
     }
}

//
// Function: PostRecvfrom
//
// Description:
//    This routine posts an overlapped WSARecvFrom on the raw socket.
//
static int PostRecvfrom(SOCKET s, char *buf, int buflen, SOCKADDR *from, 
int *fromlen, WSAOVERLAPPED *ol)
{
     WSABUF  wbuf;
     DWORD   flags,
             bytes;
     int     rc;

     wbuf.buf = buf;
     wbuf.len = buflen;

     flags = 0;

     rc = WSARecvFrom(
             s,
            &wbuf,
             1,
            &bytes,
            &flags,
             from,
             fromlen,
             ol,
             NULL
             );
     if (rc == SOCKET_ERROR)
     {
         if (WSAGetLastError() != WSA_IO_PENDING)
         {
             fprintf(stderr, "WSARecvFrom failed: %d\n", WSAGetLastError());
             return SOCKET_ERROR;
         }
     }
     return NO_ERROR;
}

//
// Function: PrintPayload
//
// Description:
//    This routine is for IPv4 only. It determines if there are any IP 
options
//    present (by seeing if the IP header length is greater than 20 
bytes) and
//    if so it prints the IP record route options.
//
static void PrintPayload(char *buf, int bytes)
{
     int     hdrlen=0,
             routes=0,
             i;

     UNREFERENCED_PARAMETER(bytes);

     if (gAddressFamily == AF_INET)
     {
         SOCKADDR_IN      hop;
         IPV4_OPTION_HDR *v4opt=NULL;
         IPV4_HDR        *v4hdr=NULL;

         hop.sin_family = (USHORT)gAddressFamily;
         hop.sin_port   = 0;

         v4hdr = (IPV4_HDR *)buf;
         hdrlen = (v4hdr->ip_verlen & 0x0F) * 4;
     }
     return;
}

//
// Function: SetTtl
//
// Description:
//    Sets the TTL on the socket.
//
static int SetTtl(SOCKET s, int ttl)
{
     int     optlevel = 0,
             option = 0,
             rc;

     rc = NO_ERROR;
     if (gAddressFamily == AF_INET)
     {
         optlevel = IPPROTO_IP;
         option   = IP_TTL;
     }
     else
     {
         rc = SOCKET_ERROR;
     }
     if (rc == NO_ERROR)
     {
         rc = setsockopt(
                 s,
                 optlevel,
                 option,
                 (char *)&ttl,
                 sizeof(ttl)
                 );
     }
     if (rc == SOCKET_ERROR && verbose)
     {
         fprintf(stderr, "SetTtl: setsockopt failed: %d\n", 
WSAGetLastError());
     }
     return rc;
}
//
// Function: ResolveAddress
//
// Description:
//    This routine resolves the specified address and returns a list of 
addrinfo
//    structure containing SOCKADDR structures representing the resolved 
addresses.
//    Note that if 'addr' is non-NULL, then getaddrinfo will resolve it 
whether
//    it is a string listeral address or a hostname.
//
static struct addrinfo *ResolveAddress(char *addr, char *port, int af, 
int type, int proto)
{
     struct addrinfo hints,
     *res = NULL;
     int             rc;

     memset(&hints, 0, sizeof(hints));
     hints.ai_flags  = ((addr) ? 0 : AI_PASSIVE);
     hints.ai_family = af;
     hints.ai_socktype = type;
     hints.ai_protocol = proto;

     rc = getaddrinfo(
             addr,
             port,
            &hints,
            &res
             );
     if (rc != 0)
     {
         if (verbose)
			fprintf(stderr, "Invalid address %s, getaddrinfo failed: %d\n", addr, 
rc);
         return NULL;
     }
     return res;
}

static int FormatAddress(SOCKADDR *sa, int salen, char *addrbuf, int 
addrbuflen)
{
     char    host[NI_MAXHOST],
             serv[NI_MAXSERV];
     int     hostlen = NI_MAXHOST,servlen = NI_MAXSERV,rc;
     HRESULT hRet;

     rc = getnameinfo(
             sa,
             salen,
             host,
             hostlen,
             serv,
             servlen,
             NI_NUMERICHOST | NI_NUMERICSERV
             );
     if (rc != 0)
     {
         return rc;
     }

     if ( (strlen(host) + strlen(serv) + 1) > (unsigned)addrbuflen)
         return WSAEFAULT;

     addrbuf[0] = '\0';

     if (sa->sa_family == AF_INET)
     {
         snprintf(addrbuf, addrbuflen, "%s:%s", host, serv);
     }
     else if (sa->sa_family == AF_INET6)
     {
         snprintf(addrbuf, addrbuflen, "[%s]:%s", host, serv);
     }

     return 0;
}
//
// Function: ping
//
// Description:
//    Setup the ICMP raw socket and create the ICMP header. Add
//    the appropriate IP option header and start sending ICMP
//    echo requests to the endpoint. For each send and receive we
//    set a timeout value so that we don't wait forever for a
//    response in case the endpoint is not responding. When we
//    receive a packet decode it.
//

int ping(PingInterface *params)
{

     WSADATA            wsd;
     WSAOVERLAPPED      recvol;
     SOCKET             s=INVALID_SOCKET;
     char              *icmpbuf=NULL;
     struct addrinfo   *dest=NULL,
                       *local=NULL;
     IPV4_OPTION_HDR    ipopt;
     struct sockaddr_in from;
     DWORD              bytes,
                        flags;
     int                packetlen=0,
                        fromlen,
                        time=0,
                        rc,
                        i,
                        status = 0;

     recvol.hEvent = WSA_INVALID_EVENT;

     // Parse the command line
     ReadArgs(params);

     // Load Winsock
     if ((rc = WSAStartup(MAKEWORD(2,2), &wsd)) != 0)
     {
         if (verbose) printf("WSAStartup() failed: %d\n", rc);
         status = -3;
         goto EXIT;
     }

     // Resolve the destination address
     dest = ResolveAddress(
             gDestination,
             "0",
             gAddressFamily,
             0,
             0
             );
     if (dest == NULL)
     {
         if (verbose) printf("bad name %s\n", gDestination);
         status = -1;
         goto CLEANUP;
     }
     gAddressFamily = dest->ai_family;

     if (gAddressFamily == AF_INET)
         gProtocol = IPPROTO_ICMP;

     // Get the bind address
     local = ResolveAddress(
             NULL,
             "0",
             gAddressFamily,
             0,
             0
             );
     if (local == NULL)
     {
         if (verbose) printf("Unable to obtain the bind address!\n");
         status = -1;
         goto CLEANUP;
     }

     // Create the raw socket
     s = socket(gAddressFamily, SOCK_RAW, gProtocol);
     if (s == INVALID_SOCKET)
     {
         if (verbose) printf("socket failed: %d\n", WSAGetLastError());
         status = -1;
         goto CLEANUP;
     }

     SetTtl(s, gTtl);

     // Figure out the size of the ICMP header and payload
     if (gAddressFamily == AF_INET)
         packetlen += sizeof(ICMP_HDR);

     // Add in the data size
     packetlen += gDataSize;

     // Allocate the buffer that will contain the ICMP request
     icmpbuf = (char *)HeapAlloc(GetProcessHeap(), HEAP_ZERO_MEMORY, 
packetlen);
     if (icmpbuf == NULL)
     {
         if (verbose) fprintf(stderr, "HeapAlloc failed: %d\n", 
GetLastError());
         status = -1;
         goto CLEANUP;
     }

     // Initialize the ICMP headers
     if (gAddressFamily == AF_INET)
     {

         InitIcmpHeader(icmpbuf, gDataSize);
     }

     // Bind the socket -- need to do this since we post a receive first
     rc = bind(s, local->ai_addr, (int)local->ai_addrlen);
     if (rc == SOCKET_ERROR)
     {
         if (verbose) fprintf(stderr, "bind failed: %d\n", 
WSAGetLastError());
         status = -1;
         goto CLEANUP;
     }

     // Setup the receive operation
     memset(&recvol, 0, sizeof(recvol));
     recvol.hEvent = WSACreateEvent();
     if (recvol.hEvent == WSA_INVALID_EVENT)
     {
         fprintf(stderr, "WSACreateEvent failed: %d\n", WSAGetLastError());
         status = -1;
         goto CLEANUP;
     }

     // Post the first overlapped receive
     fromlen = sizeof(from);
     PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, &fromlen, 
&recvol);


     // Start sending the ICMP requests
     for(i=0; i < params->TotalPackets ;i++)
     {
         // Set the sequence number and compute the checksum
         params->Seq = SetIcmpSequence(icmpbuf);
         ComputeIcmpChecksum(s, icmpbuf, packetlen, dest);

         time = GetTickCount();
         rc = sendto(
                 s,
                 icmpbuf,
                 packetlen,
                 0,
                 dest->ai_addr,
                 (int)dest->ai_addrlen
                 );
         if (rc == SOCKET_ERROR)
         {
             if (verbose) fprintf(stderr, "sendto failed: %d\n", 
WSAGetLastError());
             status = -1;
             goto CLEANUP;
         }
		params->TotalSent++;

         // Waite for a response
         rc = WaitForSingleObject((HANDLE)recvol.hEvent, 
DEFAULT_RECV_TIMEOUT);
         if (rc == WAIT_FAILED)
         {
             if (verbose) fprintf(stderr, "WaitForSingleObject failed: 
%d\n", GetLastError());
             status = -1;
             goto CLEANUP;
         }
         else if (rc == WAIT_TIMEOUT)
         {
			if (verbose)
             	printf("Request timed out.\n");

			if (params->ip[0] == 0)
				strncpy(params->ip,params->HostName,MAXIPNAME-1);
			params->ip[MAXIPNAME-1] = 0;
			if (params->Callback) {
				params->Errorcode = WSAETIMEDOUT;
				params->Timeouts++;
				params->Callback(params);
				if (params->Timeouts >= params->MaxTimeouts)
					break;
			}
         }
         else
         {
             rc = WSAGetOverlappedResult(
                    s,
                    &recvol,
                    &bytes,
                     FALSE,
                    &flags
                     );
             if (rc == FALSE)
             {
                 params->Errorcode = WSAGetLastError();
				if (params->Callback) {
					params->Callback(params);
				}
				params->Errorcode = 0;
             }
             time = GetTickCount() - time;

             WSAResetEvent(recvol.hEvent);

			params->TotalReceived++;
			if (params->ip[0] == 0)
				FormatAddress((SOCKADDR *)&from,fromlen,params->ip,MAXIPNAME-1);
			if (params->Callback) {
				params->Bytes = bytes;
				params->Callback(params);
			}
			params->Time = time;
			params->TotalTime += time;
			if (time < params->MinTime)
				params->MinTime = time;
			if (time > params->MaxTime)
				params->MaxTime = time;
			if (params->verbose) {
	            printf("Reply from ");
	            if (time == 0)
	                printf(": bytes=%d time<1ms TTL=%d\n", gDataSize, gTtl);
	            else
	                printf(": bytes=%d time=%dms TTL=%d\n", gDataSize, 
time, gTtl);
	            PrintPayload(recvbuf, bytes);
			}


             if (i < params->TotalPackets- 1)
             {
                 fromlen = sizeof(from);
                 PostRecvfrom(s, recvbuf, recvbuflen, (SOCKADDR *)&from, 
&fromlen, &recvol);
             }
         }
         Sleep(params->SleepTime);
     }

CLEANUP:

     //
     // Cleanup
     //
     if (dest)
          freeaddrinfo(dest);
     if (local)
          freeaddrinfo(local);
     if (s != INVALID_SOCKET)
         closesocket(s);
     if (recvol.hEvent != WSA_INVALID_EVENT)
         WSACloseEvent(recvol.hEvent);
     if (icmpbuf)
         HeapFree(GetProcessHeap(), 0, icmpbuf);

     WSACleanup();

EXIT:
	if (status == 0)
	   status = params->TotalReceived;
     return status;

}
-------------------------------------------------------end of ping.c


0
Reply jacob 9/24/2005 8:11:25 AM

On Thu, 22 Sep 2005 22:33:53 -0500,
ararghmail509NOSPAM@NOW.AT.arargh.com wrote:

> On Fri, 23 Sep 2005 03:16:52 GMT, Richard Sanders
> <richard@stardate.ca> wrote:
> 
> >I have taken Jacob's code verbatum from "advanced.pdf".  It compiles fine 
> >but when run, I get this error.
> >
> >"The ping.exe file is linked to missing export ws2_32.dll:getnameinfo."
> >
> >On checking out ws2_32.dll in wordpad, ws2_32.dll does not contain any 
> >referance to "getnameinfo".  
> 
> Checking MSDN library, "getnameinfo" gets no hits at all.  It is not
> the name of any API that I can see.
> 
get{name,addr}info() are the IPv6-capable replacements for
gethostby{addr,name}(). According to the MSDN at my workplace they are
in W95 and later (but I don't have such old system to test).

> >This is on win98, I also tried the ping.exe on an nt4 box with the same 
> >error poping up.
> >
> >Any idars anyone.
> Ask Jacob what the correct API call is. :-)
> 

- David.Thompson1 at worldnet.att.net
0
Reply Dave 9/29/2005 6:30:36 PM

On Thu, 29 Sep 2005 18:30:36 GMT, Dave Thompson
<david.thompson1@worldnet.att.net> wrote:

<snip>
>> 
>> Checking MSDN library, "getnameinfo" gets no hits at all.  It is not
>> the name of any API that I can see.
>> 
>get{name,addr}info() are the IPv6-capable replacements for
>gethostby{addr,name}(). 
I was checking an older copy of MSDN library.  

>According to the MSDN at my workplace they are
>in W95 and later (but I don't have such old system to test).

If so, it must need an update.  "getnameinfo" was not found when
searching DLL's in the system directory on my fairly vanilla copy of
Win98.

<snip>

-- 
ArarghMail509 at [drop the 'http://www.' from ->] http://www.arargh.com
BCET Basic Compiler Page: http://www.arargh.com/basic/index.html

To reply by email, remove the garbage from the reply address.
0
Reply ararghmail509NOSPAM 9/29/2005 7:20:45 PM

6 Replies
285 Views

(page loaded in 0.142 seconds)

Similiar Articles:













7/26/2012 5:20:25 AM


Reply: