|
|
/*++
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 mjourd Feb 20, 2002 Removed QoS 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 "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; 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) { 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 = (socklen_t)ai->ai_addrlen; memcpy(TargetAddress, ai->ai_addr, ai->ai_addrlen);
if (DoReverseLookup) { getnameinfo(ai->ai_addr, (socklen_t)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 = (socklen_t)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;
UNREFERENCED_PARAMETER(Ignored1); UNREFERENCED_PARAMETER(Ignored2);
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; 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; socklen_t addressLen; 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; IP_OPTION_INFORMATION options; unsigned char optionsData[MAX_OPT_SIZE]; unsigned char *optionPtr; BYTE currentIndex; IPAddr tempAddr; BYTE j; BYTE SRIndex = 0; BOOLEAN foundAddress = FALSE; BOOLEAN haveReply; int numRetries = DEFAULT_MAX_RETRIES; DWORD Family = AF_UNSPEC;
if (WSAStartup( 0x0101, &WsaData)) { NlsPutMsg(STDOUT, PATHPING_WSASTARTUP_FAILED, GetLastError()); return(1); }
ZeroMemory(&address, sizeof(address)); addressLen = sizeof(address);
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] = (unsigned 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': { 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 '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( (USHORT*)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( (USHORT*)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:
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); }
|