Note: This is not the complete source code--just the main source file.
You can download the full source (with include files) from our sample code archive by clicking on the diskette icons.
<%@ EnableSessionState=False LANGUAGE="VBSCRIPT" %>
<%
Option explicit
Response.Buffer = false
%>
<!--
AspAnalyzePath sample script
Demonstrates use of HexIcmp and HexLookup
This is an experimental visual traceroute of sorts.
Here's how it works:
1. Discovers the network path to the chosen host using the
standard traceroute technique - pinging the host while
incrementing the packet TTL (time-to-live) from 1.
2. Pings each hop separately to collect RTT (round-trip time)
data. The RTTs from the path discovery aren't used because
directly pinging the hops yields potentially different and
better RTT data.
3. Calculates the median of the RTTs for each hop. Taking the
median yields better results than taking the average
because it is not influenced as much by the occasional
extra-long RTT.
4. Calculates the change in RTT from one hop to the next, then
divides by two to approximate the latency in one direction.
Does not allow negative deltas
5. Graphs the hops and the latencies between them to give a
graphical view of the network path. Also does reverse
lookups for each hop. The graph is implemented in HTML, so
it is unfortunately rather crude.
Possible future improvements:
1. Calculate packet losses for each hop.
2. Improve graphing. Include packet loss data, total latency
along path, hop latencies as a percentage of the total.
3. Improve handling of RTT deltas. Sometimes a hop in the
middle of the path will consistently return higher RTT
values than hops beyond it (due to congestion, lower
priority for ICMP, or whatever). With the current scheme,
the hops after the anomalous one will get deltas of 0
(because we can't draw negative deltas), thus skewing the
picture of the path.
4. Avoid rounding numbers too early, although it doesn't
matter too much since ICMP.DLL only provides 10ms
resolution anyway.
Comments? Ideas? Do you have a better implementation? Let us
know at feedback@hexillion.com.
Copyright (C) 1998 Hexillion Technologies. All rights reserved.
-->
<!-- #include file="AuxFuncs.asp" -->
<html>
<head>
<title>Hexillion AspAnalyzePath sample</title>
</head>
<body bgcolor="#FFFFFF" text="#000000" vlink="#808080" link="#0000FF">
<%
dim oLkup, oIcmp, sLocalName, sLocalAddr, sRemoteName
set oLkup = Server.CreateObject( "Hexillion.HexLookup" )
set oIcmp = Server.CreateObject( "Hexillion.HexIcmp" )
sLocalName = request( "SERVER_NAME" )
sLocalAddr = request( "LOCAL_ADDR" )
sRemoteName = Request( "host" )
if "" = sRemoteName then sRemoteName = request( "REMOTE_HOST" )
const maxPoints = 10 '// Max number of data points per hop
dim lNumPoints
if not IsEmpty( request( "points" ) ) then
lNumPoints = Clng( request( "points" ) )
if lNumPoints < 0 then
lNumPoints = 1
elseif lNumPoints > maxPoints then
lNumPoints = maxPoints
end if
else
lNumPoints = 5
end if
%>
<table cellpadding="5" width="100%"><tr>
<td colspan="2" bgcolor="#E1EFFF"><p><font face="Arial" size="5"><strong>AspAnalyzePath sample</strong></font><br>
An experimental graphical traceroute
</td></tr>
<tr>
<td valign="top" bgcolor="#E1EFFF">
<form name="hostentry" method="POST" action="<%= request( "SCRIPT_NAME" ) %>">
<table cellpadding="5">
<tr><td align="right" valign="baseline">from</td>
<td valign="baseline"><tt><strong><%= Server.HtmlEncode( sLocalName ) %> [<%= sLocalAddr %>]</strong></tt></td></tr>
<tr><td align="right" valign="baseline">to</td>
<td valign="baseline"><input type="text" name="host" size="27" value="<%= Server.HtmlEncode( sRemoteName ) %>"></td></tr>
<tr><td align="right" valign="baseline">data points</td>
<td valign="baseline"><input type="text" name="points" size="3" value="<%= lNumPoints %>"> (higher = more accurate)</td></tr>
<tr><td align="right" valign="baseline"> </td>
<td valign="baseline"><input type="submit" value="Go" name="B1"></td></tr>
</table>
</form>
</td>
<td valign="top" bgcolor="#E1EFFF">
<table border="0" cellspacing="0" cellpadding="7">
<tr>
<td colspan="2">powered by <b><a href="http://www.hexillion.com/software/" target="_top">HexGadgets</a></b>
<br><font size="-1">
<a href="http://www.hexillion.com/samples/view_src.asp?name=AspAnalyzePath.asp" target="_blank">view source</a>
| <a href="http://www.hexillion.com/samples/" target="_top">download</a>
</font></td>
</tr>
<%
WriteLicenseRow "HexIcmp", oIcmp
WriteLicenseRow "HexLookup", oLkup
%>
</table>
</td>
</tr></table>
<%
if not IsEmpty( Request( "host" ) ) then
dim lAddr, lRecvAddr
lAddr = oLkup.LookUp( sRemoteName )
if 0 = lAddr then
Response.Write( "<p>Lookup of " & Server.HtmlEncode( sRemoteName ) & " failed.</p>" )
else
'// Display canonical name if available
if oLkup.Aliases.Count > 0 then sRemoteName = oLkup.Aliases( 1 )
response.write "<p>Collecting data on path to <tt><strong>" & Server.HtmlEncode( sRemoteName ) & " [" & oLkup.AddrToString( lAddr ) & "]</strong></tt>...</p>"
'// Discover path
const maxHops = 30 '// Max TTL to try
const maxMissing = 4 '// Max missing hops before aborting trace
const maxWait = 1000 '// Max time to wait for ping
const maxTries = 3 '// Max number of discovery retries
dim lNumHops, lMissingCount, lPathErr
redim lHopAddrs( maxHops )
Dim i, j, k, lRTT, sRTT, iMax, lErr, bAbort
i = 0
oIcmp.Timeout = maxWait
bAbort = false
Do While lHopAddrs( i ) <> lAddr And i < maxHops and not bAbort
i = i + 1
oIcmp.SendTtl = i
for j = 1 to maxTries
lRTT = oIcmp.Ping(lAddr)
If lRTT < 0 And oIcmp.Error <> hexIcmpErrTtlExpiredTransit Then
lErr = oIcmp.Error
Select Case lErr
Case hexIcmpErrReqTimedOut
'// Do nothing
Case Else
lPathErr = lErr
bAbort = True
exit for
End Select
Else
lHopAddrs( i ) = oIcmp.RecvAddr
'// Reset our count of "missing" hops
lMissingCount = 0
exit for
End If
next
if j > maxTries then
'// We have another "missing" hop
lMissingCount = lMissingCount + 1
'// Abort if we've had too many consecutive missing
if lMissingCount >= maxMissing then bAbort = true
end if
loop
if 0 <> lPathErr then
lNumHops = i - 1
else
lNumHops = i
end if
redim lHopRtts( lNumHops, lNumPoints )
redim lHopMedians( lNumHops )
redim lHopDeltas( lNumHops )
%>
<table border="0" cellpadding="3" cellspacing="0">
<tr>
<td width="80" align="right" bgcolor="#E1EFFF"><tt>hop</tt></td>
<%
for i = 1 to lNumHops
%>
<td width="40" align="right" bgcolor="#E1EFFF" valign="bottom"><tt><%= i %></tt></td>
<%
next
%>
</tr>
</table>
<%
'// Collect ping data for each hop
for j = 1 to lNumPoints
%>
<table border="0" cellpadding="3" cellspacing="0">
<tr>
<td width="80" align="right" bgcolor="#E1EFFF"><tt>rtt (ms)</tt></td>
<%
for i = 1 to lNumHops
lHopRtts( i, j ) = oIcmp.Ping( lHopAddrs( i ) )
if lHopRtts( i, j ) < 0 then
sRTT = "*"
else
sRTT = CStr( lHopRtts( i, j ) )
end if
%>
<td width="40" align="right" valign="bottom"><tt><%= sRTT %></tt></td>
<%
next
%>
</tr>
</table>
<%
next
'// Sort RTTs (for finding median)
dim lMax, lTemp
for i = 1 to lNumHops
for j = 1 to lNumPoints
lMax = j
for k = j+1 to lNumPoints
if lHopRtts( i, k ) > lHopRtts( i, lMax ) then lMax = k
next
swap lHopRtts( i, j ), lHopRtts( i, lMax )
next
next
'// Calc medians
for i = 1 to lNumHops
for j = lNumPoints to 1 step -1
if lHopRtts( i, j ) >= 0 then exit for
next
if j < 0 then
'// No data for this hop
lHopMedians( i ) = -1
else
dim lMid
lMid = (j + 1) \ 2
if CBool( j mod 2 ) then
lHopMedians( i ) = lHopRtts( i, lMid )
else
lHopMedians( i ) = (lHopRtts( i, lMid ) + lHopRtts( i, lMid + 1 )) \ 2
end if
end if
next
%>
<table border="0" cellpadding="3" cellspacing="0">
<tr>
<td width="80" align="right" bgcolor="#E1EFFF"><tt>median</tt></td>
<%
for i = 1 to lNumHops
%>
<td width="40" align="right" valign="bottom"><tt><%= lHopMedians( i ) %></tt></td>
<%
next
%>
</tr>
</table>
<%
'// Calc deltas
lMax = 0
for i = 1 to lNumHops
lHopDeltas( i ) = max( 0, (lHopMedians( i ) - lMax) \ 2 )
if lHopMedians( i ) > lMax then lMax = lHopMedians( i )
next
%>
<table border="0" cellpadding="3" cellspacing="0">
<tr>
<td width="80" align="right" bgcolor="#E1EFFF"><tt>delta/2</tt></td>
<%
for i = 1 to lNumHops
%>
<td width="40" align="right" valign="bottom"><tt><%= lHopDeltas( i ) %></tt></td>
<%
next
%>
</tr>
</table>
<p>Graphing...</p>
<table border="0" cellpadding="0" cellspacing="1">
<tr>
<td height="5" width="40" align="right"> </td>
<td height="5" bgcolor="#0000FF"><tt> </tt></td>
<td height="5" valign="bottom"><tt> [<%= oLkup.AddrToString( oLkup.LookUp( oLkup.HostName ) ) %>] <%= Server.HtmlEncode( oLkup.HostName ) %></tt></td>
</tr>
</table>
<%
'// Draw our crude little graph
const minHeight = 5
const maxHeight = 400
dim fRatio, lHeight, lTotalTime, sDelta
for i = 1 to lNumHops
lTotalTime = lTotalTime + lHopDeltas( i )
next
lTotalTime = max( lTotalTime, 1 )
fRatio = maxHeight / lTotalTime
for i = 1 to lNumHops
lHeight = max( minHeight, CLng( lHopDeltas( i ) * fRatio ) )
if lHopDeltas( i ) > 0 then
sDelta = CStr( lHopDeltas( i ) )
else
sDelta = ""
end if
%>
<table border="0" cellpadding="0" cellspacing="1">
<tr>
<td height="<%= lHeight %>" width="40" align="right"><tt><%= sDelta %> </tt></td>
<td height="<%= lHeight %>" bgcolor="#0000ff"><tt> </tt></td>
<td height="<%= lHeight %>" valign="bottom"><tt> [<%= oLkup.AddrToString( lHopAddrs( i ) ) %>] <%= Server.HtmlEncode( oLkup.ReverseLookup( lHopAddrs( i ) ) ) %></tt></td>
</tr>
</table>
<%
next
end if
end if
sub swap( a, b )
dim c
c = a
a = b
b = c
end sub
function max( a, b )
if b > a then
max = b
else
max = a
end if
end function
%>
</body>
</html>