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
|