windows-nt/Source/XPSP1/NT/net/tcpip/commands/pathping/pathping.c
2020-09-26 16:20:57 +08:00

946 lines
29 KiB
C

/*++
Copyright (c) 1999-2001 Microsoft Corporation
Module Name:
pathping.c
Abstract:
PathPing utility
Author:
Dave Thaler
Revision History:
Who When What
-------- -------- ----------------------------------------------
rajeshsu Aug 10, 1999 Added QoS support (802.1p and RSVP)
dthaler Mar 31, 2001 Added IPv6 support
Notes:
--*/
#include <nt.h>
#include <ntrtl.h>
#include <nturtl.h>
#define NOGDI
#define NOMINMAX
#include <windows.h>
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#include <io.h>
#include <nls.h>
#include <winsock2.h>
#include <ws2tcpip.h>
#include <ntddip6.h>
#include "pathqos.h"
#include "ipexport.h"
#include "icmpapi.h"
#include "nlstxt.h"
#include "pathping.h"
ULONG g_ulTimeout = DEFAULT_TIMEOUT;
ULONG g_ulInterval = MIN_INTERVAL;
ULONG g_ulNumQueries = DEFAULT_NUM_QUERIES;
HANDLE g_hIcmp = NULL;
ULONG g_ulRcvBufSize = 0x2000;
BOOLEAN g_bDoReverseLookup = TRUE;
BOOLEAN g_bDo8021P = FALSE;
BOOLEAN g_bDoRSVP = FALSE;
BOOLEAN g_bDoRSVPDiag = FALSE;
SOCKADDR_STORAGE g_ssMyAddr = {0};
socklen_t g_slMyAddrLen = 0;
BOOLEAN g_bSetAddr = FALSE;
HOP hop[MAX_HOPS];
#ifdef VXD
# define FAR _far
#endif // VXD
char SendBuffer[DEFAULT_SEND_SIZE];
char RcvBuffer[DEFAULT_RECEIVE_SIZE];
WSADATA WsaData;
struct IPErrorTable {
IP_STATUS Error; // The IP Error
DWORD ErrorNlsID; // The corresponding NLS string ID.
} ErrorTable[] =
{
{ IP_BUF_TOO_SMALL, PATHPING_BUF_TOO_SMALL },
{ IP_DEST_NET_UNREACHABLE, PATHPING_DEST_NET_UNREACHABLE },
{ IP_DEST_HOST_UNREACHABLE, PATHPING_DEST_HOST_UNREACHABLE },
{ IP_DEST_PROT_UNREACHABLE, PATHPING_DEST_PROT_UNREACHABLE },
{ IP_DEST_PORT_UNREACHABLE, PATHPING_DEST_PORT_UNREACHABLE },
{ IP_NO_RESOURCES, PATHPING_NO_RESOURCES },
{ IP_BAD_OPTION, PATHPING_BAD_OPTION },
{ IP_HW_ERROR, PATHPING_HW_ERROR },
{ IP_PACKET_TOO_BIG, PATHPING_PACKET_TOO_BIG },
{ IP_REQ_TIMED_OUT, PATHPING_REQ_TIMED_OUT },
{ IP_BAD_REQ, PATHPING_BAD_REQ },
{ IP_BAD_ROUTE, PATHPING_BAD_ROUTE },
{ IP_TTL_EXPIRED_TRANSIT, PATHPING_TTL_EXPIRED_TRANSIT },
{ IP_TTL_EXPIRED_REASSEM, PATHPING_TTL_EXPIRED_REASSEM },
{ IP_PARAM_PROBLEM, PATHPING_PARAM_PROBLEM },
{ IP_SOURCE_QUENCH, PATHPING_SOURCE_QUENCH },
{ IP_OPTION_TOO_BIG, PATHPING_OPTION_TOO_BIG },
{ IP_BAD_DESTINATION, PATHPING_BAD_DESTINATION },
{ IP_NEGOTIATING_IPSEC, PATHPING_NEGOTIATING_IPSEC },
{ IP_GENERAL_FAILURE, PATHPING_GENERAL_FAILURE }
};
void
print_addr(SOCKADDR *sa, socklen_t salen, BOOLEAN DoReverseLookup)
{
unsigned char hostname[NI_MAXHOST];
int i;
BOOLEAN didReverse = FALSE;
if (DoReverseLookup) {
i = getnameinfo(sa, salen, hostname, sizeof(hostname),
NULL, 0, NI_NAMEREQD);
if (i == NO_ERROR) {
didReverse = TRUE;
NlsPutMsg(STDOUT, PATHPING_TARGET_NAME, hostname);
}
}
i = getnameinfo(sa, salen, hostname, sizeof(hostname),
NULL, 0, NI_NUMERICHOST);
if (i != NO_ERROR) {
// This should never happen unless there is a memory problem,
// in which case the message associated with PATHPING_NO_RESOURCES
// is reasonable.
NlsPutMsg(STDOUT, PATHPING_NO_RESOURCES);
exit (1);
}
if (didReverse) {
NlsPutMsg( STDOUT, PATHPING_BRKT_IP_ADDRESS, hostname );
} else {
NlsPutMsg( STDOUT, PATHPING_IP_ADDRESS, hostname );
}
}
void
print_ip_addr(IPAddr ipv4Addr, BOOLEAN DoReverseLookup)
{
SOCKADDR_IN sin;
memset(&sin, 0, sizeof(sin));
sin.sin_family = AF_INET;
sin.sin_addr.s_addr = ipv4Addr;
print_addr((LPSOCKADDR)&sin, sizeof(sin), DoReverseLookup);
}
void
print_ipv6_addr(USHORT ipv6Addr[8], BOOLEAN DoReverseLookup)
{
SOCKADDR_IN6 sin;
memset(&sin, 0, sizeof(sin));
sin.sin6_family = AF_INET6;
memcpy(&sin.sin6_addr, ipv6Addr, sizeof(sin.sin6_addr));
print_addr((LPSOCKADDR)&sin, sizeof(sin), DoReverseLookup);
}
void
print_time(ULONG Time)
{
if (Time) {
NlsPutMsg( STDOUT, PATHPING_TIME, Time );
// printf(" %3lu ms\n", Time);
}
else {
NlsPutMsg( STDOUT, PATHPING_TIME_10MS );
// printf(" <10 ms\n");
}
}
BOOLEAN
param(
ULONG *parameter,
char **argv,
int argc,
int current,
ULONG min,
ULONG max
)
{
ULONG temp;
char *dummy;
if (current == (argc - 1) ) {
NlsPutMsg( STDOUT, PATHPING_NO_OPTION_VALUE, argv[current] );
// printf( "Value must be supplied for option %s.\n", argv[current]);
return(FALSE);
}
temp = strtoul(argv[current+1], &dummy, 0);
if (temp < min || temp > max) {
NlsPutMsg( STDOUT, PATHPING_BAD_OPTION_VALUE, argv[current] );
// printf( "Bad value for option %s.\n", argv[current]);
return(FALSE);
}
*parameter = temp;
return(TRUE);
}
BOOLEAN
ResolveTarget(
IN DWORD Family,
IN char *TargetString,
OUT SOCKADDR_STORAGE *TargetAddress,
OUT socklen_t *TargetAddressLen,
OUT char *TargetName,
IN DWORD TargetNameLen,
IN BOOLEAN DoReverseLookup
)
{
int i;
struct addrinfo hints, *ai;
TargetName[0] = '\0';
memset(&hints, 0, sizeof(hints));
hints.ai_family = Family;
hints.ai_flags = AI_NUMERICHOST;
i = getaddrinfo(TargetString, NULL, &hints, &ai);
if (i == NO_ERROR) {
*TargetAddressLen = ai->ai_addrlen;
memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
if (DoReverseLookup) {
getnameinfo(ai->ai_addr, ai->ai_addrlen,
TargetName, TargetNameLen,
NULL, 0, NI_NAMEREQD);
}
freeaddrinfo(ai);
return(TRUE);
} else {
hints.ai_flags = AI_CANONNAME;
if (getaddrinfo(TargetString, NULL, &hints, &ai) == 0) {
*TargetAddressLen = ai->ai_addrlen;
memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
strcpy(TargetName,
(ai->ai_canonname)? ai->ai_canonname : TargetString);
freeaddrinfo(ai);
return(TRUE);
}
}
return(FALSE);
} // ResolveTarget
ULONG g_ulSendsDone = 0;
void
SleepForTotal(
DWORD dwTotal
)
{
DWORD dwStopAt = GetTickCount() + dwTotal;
int iLeft = (int)dwTotal;
while (iLeft > 0) {
SleepEx(iLeft, TRUE);
iLeft = dwStopAt - GetTickCount();
}
}
VOID
EchoDone(
IN PVOID pContext,
IN PIO_STATUS_BLOCK Ignored1,
IN ULONG Ignored2
)
{
PAPC_CONTEXT pApc = (PAPC_CONTEXT)pContext;
ULONG ulNumReplies;
ULONG i;
g_ulSendsDone++;
if (g_ssMyAddr.ss_family == AF_INET) {
ulNumReplies = IcmpParseReplies(pApc->pReply4, g_ulRcvBufSize);
for (i=0; i<ulNumReplies; i++) {
if (pApc->sinAddr.sin_addr.s_addr is pApc->pReply4[i].Address) {
pApc->ulNumRcvd++;
pApc->ulRTTtotal += pApc->pReply4[i].RoundTripTime;
return;
}
}
} else {
ulNumReplies = Icmp6ParseReplies(pApc->pReply6, g_ulRcvBufSize);
for (i=0; i<ulNumReplies; i++) {
if (!memcmp(&pApc->sin6Addr.sin6_addr,
&pApc->pReply6[i].Address.sin6_addr,
sizeof(struct in6_addr))) {
pApc->ulNumRcvd++;
pApc->ulRTTtotal += pApc->pReply6[i].RoundTripTime;
return;
}
}
}
}
// now that the hop[] array is filled in, ping each one every g_ulInterval
// seconds
void
ComputeStatistics(
PIP_OPTION_INFORMATION pOptions
)
{
ULONG h, q;
int lost, rcvd, linklost, nodelost, sent, len;
ULONG ulHopCount = (ULONG)pOptions->Ttl;
// Allocate memory for replies
for (h=1; h<=ulHopCount; h++)
hop[h].pReply = LocalAlloc(LMEM_FIXED, g_ulRcvBufSize);
for (q=0; q<g_ulNumQueries; q++) {
for (h=1; h<=ulHopCount; h++) {
if (hop[h].saAddr.sa_family == AF_INET) {
// Send ping to h
IcmpSendEcho2(g_hIcmp, // handle to icmp
NULL, // no event
EchoDone, // callback function
(LPVOID)&hop[h], // parameter to pass to callback fcn
hop[h].sinAddr.sin_addr.s_addr, // destination
SendBuffer,
DEFAULT_SEND_SIZE,
pOptions,
hop[h].pReply,
g_ulRcvBufSize,
g_ulTimeout );
} else {
Icmp6SendEcho2(g_hIcmp, // handle to icmp
NULL, // no event
EchoDone, // callback function
(LPVOID)&hop[h], // parameter to pass to callback fcn
(LPSOCKADDR_IN6)&g_ssMyAddr,
&hop[h].sin6Addr,// destination
SendBuffer,
DEFAULT_SEND_SIZE,
pOptions,
hop[h].pReply,
g_ulRcvBufSize,
g_ulTimeout );
}
// Wait alertably for 'delay' ms
SleepForTotal(g_ulInterval);
}
}
// Wait alertably until Done count hits max
while (g_ulSendsDone < ulHopCount * g_ulNumQueries)
SleepEx(INFINITE, TRUE);
// Compute per-hop info
// hoprcvd is max rcvd of all hops >= h
hop[ulHopCount].ulHopRcvd = hop[ulHopCount].ulNumRcvd;
for (h=ulHopCount-1; h>0; h--)
hop[h].ulHopRcvd = MAX(hop[h].ulNumRcvd, hop[h+1].ulHopRcvd);
hop[0].ulHopRcvd = g_ulNumQueries;
}
VOID
PrintResults(
ULONG ulHopCount
)
{
ULONG h;
int sent, rcvd, lost, linklost, nodelost;
// Now output results
NlsPutMsg(STDOUT, PATHPING_STAT_HEADER, GetLastError());
// printf(" Source to Here This Node/Link\n");
// printf("Hop RTT Lost/Sent = Pct Lost/Sent = Pct Address\n");
// printf(" 0 ");
print_addr((LPSOCKADDR)&g_ssMyAddr, g_slMyAddrLen, g_bDoReverseLookup);
NlsPutMsg(STDOUT, PATHPING_CR);
// printf("\n");
for (h=1; h<=ulHopCount; h++) {
sent = g_ulNumQueries;
rcvd = hop[h].ulNumRcvd;
lost = sent - rcvd;
linklost = hop[h-1].ulHopRcvd - hop[h].ulHopRcvd;
nodelost = hop[h].ulHopRcvd - hop[h].ulNumRcvd;
// Display previous link stats
// printf( " %4d/%4d =%3.0f%% |\n",
// linklost, sent, 100.0*linklost/sent);
NlsPutMsg(STDOUT, PATHPING_STAT_LINK,
linklost, sent, 100*linklost/sent);
if (rcvd)
NlsPutMsg(STDOUT, PATHPING_HOP_RTT, h, hop[h].ulRTTtotal/rcvd);
else
NlsPutMsg(STDOUT, PATHPING_HOP_NO_RTT, h);
// printf("%3d ", h);
// if (!rcvd)
// printf(" --- ");
#if 0
// else if (hop[h].ulRTTtotal/rcvd == 0)
// printf(" <10ms ");
#endif
// else
// printf("%4dms ", hop[h].ulRTTtotal/rcvd);
// printf("%4d/%4d =%3.0f%% ", lost, sent, 100.0*lost/sent);
// printf("%4d/%4d =%3.0f%% ", nodelost, sent, 100.0*nodelost/sent);
NlsPutMsg(STDOUT, PATHPING_STAT_LOSS,
lost, sent, 100*lost/sent);
NlsPutMsg(STDOUT, PATHPING_STAT_LOSS,
nodelost, sent, 100*nodelost/sent);
if (!hop[h].saAddr.sa_family) {
hop[h].saAddr.sa_family = g_ssMyAddr.ss_family;
}
print_addr(&hop[h].saAddr, g_slMyAddrLen, g_bDoReverseLookup);
NlsPutMsg(STDOUT, PATHPING_CR);
// printf("\n");
}
}
BOOLEAN
SetFamily(DWORD *Family, DWORD Value, char *arg)
{
if ((*Family != AF_UNSPEC) && (*Family != Value)) {
NlsPutMsg(STDOUT, PATHPING_FAMILY, arg,
(Value==AF_INET)? "IPv4" : "IPv6");
return FALSE;
}
*Family = Value;
return TRUE;
}
int __cdecl
main(int argc, char **argv)
{
SOCKADDR_STORAGE address, replyAddress;
socklen_t addressLen, replyAddressLen;
USHORT RcvSize;
BOOL result;
DWORD numberOfReplies;
DWORD status;
PICMP_ECHO_REPLY reply4;
PICMPV6_ECHO_REPLY reply6;
char hostname[NI_MAXHOST], literal[INET6_ADDRSTRLEN];
char *arg;
int i;
ULONG maximumHops = DEFAULT_MAXIMUM_HOPS;
BOOLEAN computeStats = FALSE;
IP_OPTION_INFORMATION options;
char optionsData[MAX_OPT_SIZE];
char *optionPtr;
BYTE currentIndex;
IPAddr tempAddr;
BYTE j;
BYTE SRIndex = 0;
BOOLEAN foundAddress = FALSE;
BOOLEAN haveReply;
int numRetries = DEFAULT_MAX_RETRIES;
ULONG intvl = MIN_INTERVAL;
DWORD Family = AF_UNSPEC;
if (WSAStartup( 0x0101, &WsaData)) {
NlsPutMsg(STDOUT, PATHPING_WSASTARTUP_FAILED, GetLastError());
return(1);
}
options.Ttl = 1;
options.Tos = DEFAULT_TOS;
options.Flags = DEFAULT_FLAGS;
options.OptionsSize = 0;
options.OptionsData = optionsData;
if (argc < 2) {
NlsPutMsg( STDOUT, PATHPING_USAGE, argv[0] );
goto error_exit;
}
//
// process command line
//
for (i=1; i < argc; i++) {
arg = argv[i];
if ((arg[0] == '-') || (arg[0] == '/')) {
switch(arg[1]) {
case '?':
NlsPutMsg(STDOUT, PATHPING_USAGE, argv[0]);
goto error_exit;
case '4':
if (!SetFamily(&Family, AF_INET, arg)) {
goto error_exit;
}
break;
case '6':
if (!SetFamily(&Family, AF_INET6, arg)) {
goto error_exit;
}
break;
case 'g': // Loose source routing
// Only implemented for IPv4 so far
if (!SetFamily(&Family, AF_INET, arg)) {
goto error_exit;
}
currentIndex = options.OptionsSize;
if ((currentIndex + 7) > MAX_OPT_SIZE) {
NlsPutMsg(STDOUT, PATHPING_TOO_MANY_OPTIONS);
goto error_exit;
}
optionPtr = options.OptionsData;
optionPtr[currentIndex] = (char) IP_OPT_LSRR;
optionPtr[currentIndex+1] = 3;
optionPtr[currentIndex + 2] = 4; // Set initial pointer value
options.OptionsSize += 3;
while ( (i < (argc - 2)) && (*argv[i+1] != '-')) {
if ((currentIndex + 7) > MAX_OPT_SIZE) {
NlsPutMsg(STDOUT, PATHPING_TOO_MANY_OPTIONS);
goto error_exit;
}
arg = argv[++i];
tempAddr = inet_addr(arg);
if (tempAddr == INADDR_NONE) {
NlsPutMsg(
STDOUT,
PATHPING_BAD_ROUTE_ADDRESS,
arg
);
// printf("Bad route specified for loose source route");
goto error_exit;
}
j = optionPtr[currentIndex+1];
*(ULONG UNALIGNED *)&optionPtr[j+currentIndex] = tempAddr;
optionPtr[currentIndex+1] += 4;
options.OptionsSize += 4;
}
SRIndex = optionPtr[currentIndex+1] + currentIndex;
optionPtr[currentIndex+1] += 4; // Save space for dest. addr
options.OptionsSize += 4;
break;
case 'h':
if (!param(&maximumHops, argv, argc, i, 1, 255)) {
goto error_exit;
}
i++;
break;
case 'i':
{
unsigned char tmphostname[NI_MAXHOST];
arg = argv[++i];
if (ResolveTarget(Family,
arg,
&g_ssMyAddr,
&g_slMyAddrLen,
tmphostname,
sizeof(tmphostname),
FALSE)) {
g_bSetAddr = TRUE;
}
}
break;
case 'n':
g_bDoReverseLookup = FALSE;
break;
case 'p':
if (!param(&g_ulInterval, argv, argc, i, 1, 0xffffffff)) {
goto error_exit;
}
i++;
break;
case 'q':
if (!param(&g_ulNumQueries, argv, argc, i, 1, 255)) {
goto error_exit;
}
i++;
break;
case 'R':
// Only implemented for IPv4 so far
if (!SetFamily(&Family, AF_INET, arg)) {
goto error_exit;
}
g_bDoRSVP = TRUE;
break;
case 'P':
// Only implemented for IPv4 so far
if (!SetFamily(&Family, AF_INET, arg)) {
goto error_exit;
}
g_bDoRSVPDiag = TRUE;
break;
case 'T':
// Only implemented for IPv4 so far
if (!SetFamily(&Family, AF_INET, arg)) {
goto error_exit;
}
g_bDo8021P = TRUE;
break;
case 'w':
if (!param(&g_ulTimeout, argv, argc, i, 1, 0xffffffff)) {
goto error_exit;
}
i++;
break;
default:
NlsPutMsg(STDOUT, PATHPING_INVALID_SWITCH, argv[i]);
NlsPutMsg(STDOUT, PATHPING_USAGE);
goto error_exit;
break;
}
} else {
foundAddress = TRUE;
if ( !ResolveTarget(Family,
argv[i],
&address,
&addressLen,
hostname,
sizeof(hostname),
g_bDoReverseLookup) )
{
NlsPutMsg( STDOUT, PATHPING_MESSAGE_1, argv[i] );
// printf( "Unable to resolve target name %s.\n", argv[i]);
goto error_exit;
}
}
}
if (!foundAddress) {
NlsPutMsg(STDOUT, PATHPING_NO_ADDRESS);
NlsPutMsg(STDOUT, PATHPING_USAGE);
goto error_exit;
}
if (SRIndex != 0) {
*(ULONG UNALIGNED *)&options.OptionsData[SRIndex] = ((LPSOCKADDR_IN)&address)->sin_addr.s_addr;
}
Family = address.ss_family;
if (Family == AF_INET) {
g_hIcmp = IcmpCreateFile();
} else {
g_hIcmp = Icmp6CreateFile();
}
if (g_hIcmp == INVALID_HANDLE_VALUE) {
status = GetLastError();
NlsPutMsg( STDOUT, PATHPING_MESSAGE_2, status );
// printf( "Unable to contact IP driver. Error code %d.\n", status);
goto error_exit;
}
getnameinfo((LPSOCKADDR)&address, addressLen, literal, sizeof(literal),
NULL, 0, NI_NUMERICHOST);
if (hostname[0]) {
NlsPutMsg(
STDOUT,
PATHPING_HEADER1,
hostname,
literal,
maximumHops
);
}
else {
NlsPutMsg(
STDOUT,
PATHPING_HEADER2,
literal,
maximumHops
);
}
// Get local IP address
if (!g_bSetAddr)
{
SOCKET s = socket(address.ss_family, SOCK_RAW, 0);
DWORD BytesReturned;
WSAIoctl(s, SIO_ROUTING_INTERFACE_QUERY,
&address, sizeof address,
&g_ssMyAddr, sizeof g_ssMyAddr,
&BytesReturned, NULL, NULL);
g_slMyAddrLen = BytesReturned;
closesocket(s);
NlsPutMsg( STDOUT, PATHPING_MESSAGE_4, 0);
print_addr((LPSOCKADDR)&g_ssMyAddr, g_slMyAddrLen,
g_bDoReverseLookup);
NlsPutMsg(STDOUT, PATHPING_CR);
}
// First we need to find out the path, so we
//
while((options.Ttl <= maximumHops) && (options.Ttl != 0)) {
NlsPutMsg( STDOUT, PATHPING_MESSAGE_4, (UINT)options.Ttl );
// printf("[%3lu] ", (UINT)SendOpts.Ttl);
haveReply = FALSE;
for (i=0; i<numRetries; i++) {
if (Family == AF_INET) {
numberOfReplies = IcmpSendEcho2( g_hIcmp,
0,
NULL,
NULL,
((LPSOCKADDR_IN)&address)->sin_addr.s_addr,
SendBuffer,
DEFAULT_SEND_SIZE,
&options,
RcvBuffer,
DEFAULT_RECEIVE_SIZE,
g_ulTimeout );
if (numberOfReplies == 0) {
status = GetLastError();
reply4 = NULL;
} else {
reply4 = (PICMP_ECHO_REPLY) RcvBuffer;
status = reply4->Status;
}
if (status == IP_SUCCESS) {
print_ip_addr(
reply4->Address,
g_bDoReverseLookup
);
NlsPutMsg(STDOUT, PATHPING_CR);
ZeroMemory(&hop[options.Ttl], sizeof(HOP));
hop[options.Ttl].sinAddr.sin_family = AF_INET;
hop[options.Ttl].sinAddr.sin_addr.s_addr = reply4->Address;
goto loop_end;
}
if (status == IP_TTL_EXPIRED_TRANSIT) {
ZeroMemory(&hop[options.Ttl], sizeof(HOP));
hop[options.Ttl].sinAddr.sin_family = AF_INET;
hop[options.Ttl].sinAddr.sin_addr.s_addr = reply4->Address;
break;
}
if (status == IP_REQ_TIMED_OUT) {
NlsPutMsg(STDOUT, PATHPING_NO_REPLY_TIME);
// printf(".");
continue;
}
if (status < IP_STATUS_BASE) {
NlsPutMsg( STDOUT, PATHPING_MESSAGE_7, status );
// printf("Transmit error: code %lu\n", status);
continue;
}
//
// Fatal error.
//
if (reply4 != NULL) {
print_ip_addr(
reply4->Address,
g_bDoReverseLookup
);
NlsPutMsg( STDOUT, PATHPING_MESSAGE_6 );
// printf(" reports: ");
}
} else {
numberOfReplies = Icmp6SendEcho2(g_hIcmp,
0,
NULL,
NULL,
(LPSOCKADDR_IN6)&g_ssMyAddr,
(LPSOCKADDR_IN6)&address,
SendBuffer,
DEFAULT_SEND_SIZE,
&options,
RcvBuffer,
DEFAULT_RECEIVE_SIZE,
g_ulTimeout );
if (numberOfReplies == 0) {
status = GetLastError();
reply6 = NULL;
} else {
reply6 = (PICMPV6_ECHO_REPLY) RcvBuffer;
status = reply6->Status;
}
if (status == IP_SUCCESS) {
print_ipv6_addr(
reply6->Address.sin6_addr,
g_bDoReverseLookup
);
NlsPutMsg(STDOUT, PATHPING_CR);
ZeroMemory(&hop[options.Ttl], sizeof(HOP));
hop[options.Ttl].sin6Addr.sin6_family = AF_INET6;
memcpy(&hop[options.Ttl].sin6Addr.sin6_addr.s6_words,
reply6->Address.sin6_addr,
sizeof(reply6->Address.sin6_addr));
hop[options.Ttl].sin6Addr.sin6_scope_id = reply6->Address.sin6_scope_id;
goto loop_end;
}
if (status == IP_TTL_EXPIRED_TRANSIT) {
ZeroMemory(&hop[options.Ttl], sizeof(HOP));
hop[options.Ttl].sin6Addr.sin6_family = AF_INET6;
memcpy(&hop[options.Ttl].sin6Addr.sin6_addr.s6_words,
reply6->Address.sin6_addr,
sizeof(reply6->Address.sin6_addr));
hop[options.Ttl].sin6Addr.sin6_scope_id = reply6->Address.sin6_scope_id;
break;
}
if (status == IP_REQ_TIMED_OUT) {
NlsPutMsg(STDOUT, PATHPING_NO_REPLY_TIME);
// printf(".");
continue;
}
if (status < IP_STATUS_BASE) {
NlsPutMsg( STDOUT, PATHPING_MESSAGE_7, status );
// printf("Transmit error: code %lu\n", status);
continue;
}
//
// Fatal error.
//
if (reply6 != NULL) {
print_ipv6_addr(
reply6->Address.sin6_addr,
g_bDoReverseLookup
);
NlsPutMsg( STDOUT, PATHPING_MESSAGE_6 );
// printf(" reports: ");
}
}
for (i = 0;
( ErrorTable[i].Error != status &&
ErrorTable[i].Error != IP_GENERAL_FAILURE
);
i++
);
NlsPutMsg( STDOUT, ErrorTable[i].ErrorNlsID );
// printf("%s.\n", ErrorTable[i].ErrorString);
goto loop_end;
}
if (i==numRetries)
break;
print_addr(&hop[options.Ttl].saAddr,
g_slMyAddrLen,
g_bDoReverseLookup );
NlsPutMsg(STDOUT, PATHPING_CR);
options.Ttl++;
}
loop_end:
if(g_bDo8021P)
{
QoSCheck8021P(((LPSOCKADDR_IN)&address)->sin_addr.s_addr, (ULONG)options.Ttl);
}
if(g_bDoRSVP)
{
QoSCheckRSVP(1, (ULONG)options.Ttl);
}
if(g_bDoRSVPDiag)
{
QoSDiagRSVP(1, (ULONG)options.Ttl, TRUE);
}
NlsPutMsg(STDOUT, PATHPING_COMPUTING, options.Ttl * g_ulInterval * g_ulNumQueries / 1000);
// Okay, now that we have the path, we want to go back and
// compute statistics over numQueries queries sent every intvl
// seconds.
ComputeStatistics(&options);
PrintResults((ULONG)options.Ttl);
NlsPutMsg( STDOUT, PATHPING_MESSAGE_8 );
// printf("\nTrace complete.\n");
IcmpCloseHandle(g_hIcmp);
WSACleanup();
return(0);
error_exit:
WSACleanup();
return(1);
}