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>