rb-wartslib 0.9.11 → 0.9.12

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
@@ -0,0 +1,13 @@
1
+ require 'rubygems'
2
+ require 'wartslib'
3
+
4
+ file = Warts::File::open ARGV[0]
5
+ file.add_filters Warts::File::TRACE
6
+
7
+ count = 0
8
+ while (trace = file.read)
9
+ count += 1
10
+ end
11
+
12
+ file.close
13
+ puts count
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ num_traces = 0
7
+ Warts::File.open(ARGV[0]) do |file|
8
+ file.add_filters Warts::File::TRACE, Warts::File::LIST
9
+ file.read do |element|
10
+ case element.element_type
11
+ when Warts::File::TRACE
12
+ num_traces += 1
13
+ when Warts::File::LIST
14
+ puts " id: " + element.id.to_s
15
+ puts " name: " + element.name
16
+ puts " descr: " + element.descr
17
+ puts "monitor: " + element.monitor
18
+ end
19
+ end
20
+ end
21
+
22
+ puts "# traces: " + num_traces.to_s
@@ -0,0 +1,20 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ def t(timestamp)
7
+ timestamp.to_s + " (" + Time.at(timestamp).to_s + ")"
8
+ end
9
+
10
+ Warts::File.open(ARGV[0]) do |file|
11
+ file.add_filters Warts::File::TRACE
12
+ trace = file.read
13
+ if trace
14
+ cycle = trace.cycle
15
+ puts " id: " + cycle.id.to_s
16
+ puts "start_time: " + t(cycle.start_time)
17
+ puts " stop_time: " + t(cycle.stop_time)
18
+ puts " hostname: " + cycle.hostname
19
+ end
20
+ end
@@ -0,0 +1,36 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ CYCLE_TYPE = {
7
+ Warts::File::CYCLE_START => "start",
8
+ Warts::File::CYCLE_STOP => "stop",
9
+ Warts::File::CYCLE_DEF => "def"
10
+ }
11
+
12
+ def t(timestamp)
13
+ timestamp.to_s + " (" + Time.at(timestamp).to_s + ")"
14
+ end
15
+
16
+ num_traces = 0
17
+ Warts::File.open(ARGV[0]) do |file|
18
+ file.add_filters Warts::File::TRACE, Warts::File::CYCLE_START,
19
+ Warts::File::CYCLE_STOP, Warts::File::CYCLE_DEF
20
+
21
+ file.read do |element|
22
+ case element.element_type
23
+ when Warts::File::TRACE
24
+ num_traces += 1
25
+ when Warts::File::CYCLE_START, Warts::File::CYCLE_STOP,
26
+ Warts::File::CYCLE_DEF
27
+ puts "\n===> cycle " + CYCLE_TYPE[element.element_type]
28
+ puts " id: " + element.id.to_s
29
+ puts "start_time: " + t(element.start_time)
30
+ puts " stop_time: " + t(element.stop_time)
31
+ puts " hostname: " + element.hostname
32
+ end
33
+ end
34
+ end
35
+
36
+ puts "# traces: " + num_traces.to_s
@@ -0,0 +1,17 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ out = Warts::File::open "out.warts", "w"
7
+
8
+ Warts::File::open(ARGV[0]) do |file|
9
+ file.add_filters Warts::File::TRACE
10
+ file.read do |trace|
11
+ if trace.dest_responded? && trace.path_length > 5
12
+ out.write trace
13
+ end
14
+ end
15
+ end
16
+
17
+ out.close
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ out = Warts::File::open "out.warts", "w"
7
+
8
+ Warts::File::open(ARGV[0]) do |file|
9
+ file.add_filters Warts::File::TRACE, Warts::File::CYCLE_START,
10
+ Warts::File::CYCLE_STOP
11
+ file.read do |element|
12
+ if element.element_type == Warts::File::TRACE
13
+ if element.dest_responded? && element.path_length > 5
14
+ out.write element
15
+ end
16
+ else
17
+ out.write element
18
+ end
19
+ end
20
+ end
21
+
22
+ out.close
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ out = Warts::File::open "out.txt", "w", Warts::File::TRACEROUTE
7
+
8
+ Warts::File::open(ARGV[0]) do |file|
9
+ file.add_filters Warts::File::TRACE
10
+ file.read do |trace|
11
+ out.write trace
12
+ end
13
+ end
14
+
15
+ out.close
@@ -0,0 +1,13 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ out = Warts::File::open $stdout, "w", Warts::File::TRACEROUTE
7
+
8
+ Warts::File::open(ARGV[0]) do |file|
9
+ file.add_filters Warts::File::TRACE
10
+ file.read do |trace|
11
+ out.write trace
12
+ end
13
+ end
@@ -0,0 +1,28 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ out = Warts::File::open "out.warts", "w"
7
+
8
+ cycle = nil
9
+ Warts::File.open(ARGV[0]) do |file|
10
+ file.add_all_filters
11
+ file.read do |element|
12
+ case element.element_type
13
+ when Warts::File::TRACE
14
+ element.cycle = cycle
15
+
16
+ when Warts::File::CYCLE_START, Warts::File::CYCLE_DEF,
17
+ Warts::File::CYCLE_STOP
18
+ element = element.derive(:id => 5, :hostname => "foo.bar.com")
19
+ unless element.element_type == Warts::File::CYCLE_STOP
20
+ cycle = element
21
+ end
22
+ end
23
+
24
+ out.write element
25
+ end
26
+ end
27
+
28
+ out.close
@@ -0,0 +1,29 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ out = Warts::File::open "out.warts", "w"
7
+
8
+ cycle = nil
9
+ Warts::File.open(ARGV[0]) do |file|
10
+ file.add_all_filters
11
+ file.read do |element|
12
+ case element.element_type
13
+ when Warts::File::TRACE
14
+ element.cycle = cycle
15
+
16
+ when Warts::File::CYCLE_START, Warts::File::CYCLE_DEF,
17
+ Warts::File::CYCLE_STOP
18
+ list = element.list.derive(:name => "dnssurvey")
19
+ element = element.derive(:id => 5, :list => list)
20
+ unless element.element_type == Warts::File::CYCLE_STOP
21
+ cycle = element
22
+ end
23
+ end
24
+
25
+ out.write element
26
+ end
27
+ end
28
+
29
+ out.close
@@ -0,0 +1,10 @@
1
+ require 'rubygems'
2
+ require 'wartslib'
3
+
4
+ Warts::File::open(ARGV[0]) do |file|
5
+ file.add_filters Warts::File::TRACE
6
+
7
+ count = 0
8
+ file.read { count += 1 }
9
+ puts count
10
+ end
@@ -0,0 +1,16 @@
1
+ require 'rubygems'
2
+ require 'wartslib'
3
+
4
+ Warts::File::open(ARGV[0]) do |file|
5
+ file.add_filters Warts::File::TRACE
6
+
7
+ count = 0
8
+ file.read do |trace|
9
+ if trace.dest_responded? && trace.path_length > 5
10
+ print trace.start, " ", trace.dst, " ", trace.path_length, "\n"
11
+ count += 1
12
+ end
13
+ end
14
+
15
+ puts count
16
+ end
@@ -0,0 +1,44 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ num_traces = 0
7
+ num_responding = 0
8
+ stop_reason = Hash.new 0
9
+ hop_histogram = Hash.new 0
10
+
11
+ Warts::File.open(ARGV[0]) do |file|
12
+ file.add_filters Warts::File::TRACE
13
+ file.read do |trace|
14
+ num_traces += 1
15
+ num_responding += 1 if trace.dest_responded?
16
+ stop_reason[trace.stop_reason] += 1
17
+ hop_histogram[trace.path_length] += 1
18
+ end
19
+ end
20
+
21
+ puts "%8d traces" % [num_traces]
22
+ puts "%8d responding" % [num_responding]
23
+
24
+ # from scamper_trace.h:SCAMPER_TRACE_STOP_*
25
+ stop_text = {
26
+ 0 => "none (null reason)",
27
+ 1 => "completed (got an ICMP port unreach)",
28
+ 2 => "unreach (got an other ICMP unreach code)",
29
+ 3 => "icmp (got an ICMP msg, not unreach)",
30
+ 4 => "loop (loop detected)",
31
+ 5 => "dead (unresponsive target)",
32
+ 6 => "error (sendto error)"
33
+ }
34
+ stop_text.default = "<<UNKNOWN STOP CODE>>"
35
+
36
+ puts
37
+ stop_reason.to_a.sort.each do |k, v|
38
+ puts "%8d stop reason %d, %s" % [v, k, stop_text[k]]
39
+ end
40
+
41
+ puts
42
+ hop_histogram.to_a.sort.each do |k, v|
43
+ puts "%8d %d hops" % [v, k]
44
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ Warts::File.open(ARGV[0]) do |file|
7
+ file.add_filters Warts::File::TRACE
8
+ file.read do |trace|
9
+ puts "trace to " + trace.dst
10
+ (0 ... trace.hop_count).each do |i|
11
+ puts " #{i+1} " + (trace.hop_addr(i) || "*")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,14 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ Warts::File.open(ARGV[0]) do |file|
7
+ file.add_filters Warts::File::TRACE
8
+ file.read do |trace|
9
+ puts "trace to " + trace.dst
10
+ trace.each_hop do |i, exists|
11
+ puts " #{i+1} " + (exists ? trace.hop_addr(i) : "*")
12
+ end
13
+ end
14
+ end
@@ -0,0 +1,22 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ Warts::File.open(ARGV[0]) do |file|
7
+ file.add_filters Warts::File::TRACE
8
+ file.read do |trace|
9
+ puts "trace to " + trace.dst
10
+ trace.each_hop do |hop, exists|
11
+ print " #{hop+1}"
12
+ if exists
13
+ trace.each_response(hop) do |response|
14
+ print " ", trace.hop_addr(hop, response)
15
+ end
16
+ puts
17
+ else
18
+ puts " *"
19
+ end
20
+ end
21
+ end
22
+ end
@@ -0,0 +1,15 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ Warts::File.open(ARGV[0]) do |file|
7
+ file.add_filters Warts::File::TRACE
8
+ file.read do |trace|
9
+ puts "trace to " + trace.dst
10
+ trace.each_hop_and_response do |hop, response, hop_exists|
11
+ printf " hop=%d, resp=%d: %s\n", hop, response,
12
+ (hop_exists ? trace.hop_addr(hop, response) : "*")
13
+ end
14
+ end
15
+ end
@@ -0,0 +1,16 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'rubygems'
4
+ require 'wartslib'
5
+
6
+ Warts::File.open(ARGV[0]) do |file|
7
+ file.add_filters Warts::File::TRACE
8
+ trace = file.read
9
+ if trace
10
+ list = trace.list
11
+ puts " id: " + list.id.to_s
12
+ puts " name: " + list.name
13
+ puts " descr: " + list.descr
14
+ puts "monitor: " + list.monitor
15
+ end
16
+ end
@@ -0,0 +1,950 @@
1
+ <!DOCTYPE HTML PUBLIC "-//W3C//DTD HTML 4.01 Transitional//EN" "http://www.w3.org/TR/html4/loose.dtd">
2
+ <html>
3
+ <head>
4
+ <title>rb-wartslib: Tutorial</title>
5
+ <meta http-equiv="Content-Type" content="text/html; charset=ISO-8859-1">
6
+ <link rel="stylesheet" type="text/css" href="layout.css">
7
+ <link rel="stylesheet" type="text/css" href="style.css">
8
+ <link rel="stylesheet" type="text/css" href="ruby.css">
9
+ </head>
10
+
11
+ <body>
12
+
13
+ <div class="twikiTopBar">
14
+ <div class="twikiTopBarContents">
15
+ <h1 class="pagetitle">rb-wartslib: Ruby Warts Library</h1>
16
+ </div>
17
+ </div>
18
+
19
+ <a name="PageTop"></a>
20
+ <div class="twikiLeftBar">
21
+ <div class="twikiLeftBarContents">
22
+ <ul>
23
+ <li> <a href="index.html">Project Home Page</a></li>
24
+ <li> <a href="http://rubyforge.org/projects/rb-wartslib/">RubyForge Page</a></li>
25
+ </ul>
26
+ <hr>
27
+ <ul>
28
+ <li> <a href="index.html#installation">Installation</a></li>
29
+ <li> <a href="tutorial.html"><b>Tutorial</b></a></li>
30
+ <li> <a href="#basic_usage">&nbsp;&nbsp;&bull; Basic Usage</a></li>
31
+ <li> <a href="#trace_attributes">&nbsp;&nbsp;&bull; Trace Attributes</a></li>
32
+ <li> <a href="#hop_attributes">&nbsp;&nbsp;&bull; Hop Attributes</a></li>
33
+ <li> <a href="#list_attributes">&nbsp;&nbsp;&bull; List Attributes</a></li>
34
+ <li> <a href="#cycle_attributes">&nbsp;&nbsp;&bull; Cycle Attributes</a></li>
35
+ <li> <a href="#writing_files">&nbsp;&nbsp;&bull; Writing Files</a></li>
36
+ <li> <a href="#modifying_data">&nbsp;&nbsp;&bull; Modifying Data</a></li>
37
+ <li> <a href="reference.html">Class Reference</a></li>
38
+ <li> <a href="samples.html">Sample Scripts</a></li>
39
+ </ul>
40
+ <hr>
41
+ <ul>
42
+ <li> <a href="index.html#contact">Contact</a></li>
43
+ <li> <a href="index.html#license">License</a></li>
44
+ </ul>
45
+ </div></div>
46
+
47
+ <div class="twikiMain">
48
+ <div class="twikiTopic">
49
+ <h1>Tutorial</h1>
50
+
51
+ <h2><a name="basic_usage"></a>Basic Usage</h2>
52
+ <p>
53
+ Only a minimal amount of code is needed to use <i>rb-wartslib</i>, as the
54
+ following script shows. This script counts the number of traces in a file.
55
+ </p>
56
+
57
+ <!-- 1. count =========================================================== -->
58
+ <pre class="ruby snippet">
59
+ <span class="comment">#!/usr/bin/env ruby</span>
60
+
61
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">rubygems</span><span class="punct">'</span>
62
+ <span class="ident">require</span> <span class="punct">'</span><span class="string">wartslib</span><span class="punct">'</span>
63
+
64
+ <span class="ident">file</span> <span class="punct">=</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span> <span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">]</span>
65
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
66
+
67
+ <span class="ident">count</span> <span class="punct">=</span> <span class="number">0</span>
68
+ <span class="keyword">while</span> <span class="punct">(</span><span class="ident">trace</span> <span class="punct">=</span> <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span><span class="punct">)</span>
69
+ <span class="ident">count</span> <span class="punct">+=</span> <span class="number">1</span>
70
+ <span class="keyword">end</span>
71
+
72
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">close</span>
73
+ <span class="ident">puts</span> <span class="ident">count</span>
74
+ </pre>
75
+
76
+ <p>
77
+ You use the warts library in your scripts with the statement <code>require
78
+ 'wartslib'</code>. There are no other <code>require</code> statements
79
+ (other than <code>require 'rubygems'</code>) or other setup work you need
80
+ to worry about. As you can see, everything is contained inside
81
+ the <code>Warts</code> top-level module. The library is small, so there
82
+ are only a handful of classes inside the <code>Warts</code> module.
83
+ </p>
84
+
85
+ <p>
86
+ The Ruby binding has transparent support for reading (but not writing)
87
+ files compressed with <a href="http://www.gzip.org/">gzip</a>,
88
+ <a href="http://www.bzip.org/">bzip2</a>, or
89
+ <a href="http://www.lzop.org/">lzop</a>. In fact,
90
+ the above example script (call it <code>count-traces</code>) will
91
+ automatically work as-is on compressed files; for example:
92
+ </p>
93
+
94
+ <pre class="snippet">
95
+ <span class="shell_command">$ ./count-traces 00024353.hourly.l7.t1.20071031-19.mnl-ph.warts.gz</span>
96
+ <span class="command_output">17496</span>
97
+ </pre>
98
+
99
+ <p>
100
+ You can manually specify the input file type with a parameter to
101
+ the <code>Warts::File::open</code> method, but it is often easier to just
102
+ let the library figure it out; for example, the above script works unchanged
103
+ on an <a href="http://www.caida.org/tools/utilities/arts/">arts++</a> file:
104
+ </p>
105
+
106
+ <pre class="snippet">
107
+ <span class="shell_command">$ ./count-traces l006.mwest.20070404_000.arts</span>
108
+ <span class="command_output">155830</span>
109
+ </pre>
110
+
111
+ <p>
112
+ Another convenient feature of the library is its support of Ruby blocks.
113
+ For example, we can minimize the above script even further by rewriting it
114
+ to use blocks (from now on, we will leave out the two <code>require</code>
115
+ lines in code listings):
116
+ </p>
117
+
118
+ <!-- 2. count+blocks ==================================================== -->
119
+ <pre class="ruby snippet">
120
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span><span class="punct">(<span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">]</span>)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
121
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
122
+
123
+ <span class="ident">count</span> <span class="punct">=</span> <span class="number">0</span>
124
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="punct">{</span> <span class="ident">count</span> <span class="punct">+=</span> <span class="number">1</span> <span class="punct">}</span>
125
+ <span class="ident">puts</span> <span class="ident">count</span>
126
+ <span class="keyword">end</span>
127
+ </pre>
128
+
129
+ <p>
130
+ The advantage to using a block for <code>Warts::File::open</code> is that
131
+ the file is closed for you when the block finishes or if an exception occurs.
132
+ </p>
133
+
134
+
135
+ <h2><a name="trace_attributes"></a>Accessing Trace Attributes</h2>
136
+
137
+ <p>
138
+ Trace objects are instances of <code>Warts::Trace</code>. Once you get a
139
+ trace from <code>Warts::File#read</code>, you can use accessor methods to
140
+ examine both the data and the metadata of a traceroute
141
+ path. <code>Warts::Trace</code> also provides a number of convenience methods.
142
+ </p>
143
+
144
+ <p>
145
+ For example, the following script gives a count of the traces that have
146
+ both a responding destination and a path length greater than 5. For these
147
+ traces, it prints out the trace timestamp, destination IP address, and the
148
+ path length.
149
+ </p>
150
+
151
+ <!--- 3. count+resp ------------------------------------------------------>
152
+ <pre class="ruby snippet">
153
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span><span class="punct">(<span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">]</span>)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
154
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
155
+
156
+ <span class="ident">count</span> <span class="punct">=</span> <span class="number">0</span>
157
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
158
+ <span class="keyword">if</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dest_responded?</span> <span class="punct">&amp;&amp;</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">path_length</span> <span class="punct">&gt;</span> <span class="number">5</span>
159
+ <span class="ident">print</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">start</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string"> </span><span class="punct">&quot;,</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dst</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string"> </span><span class="punct">&quot;,</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">path_length</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string"><span class="escape">\n</span></span><span class="punct">&quot;</span>
160
+ <span class="ident">count</span> <span class="punct">+=</span> <span class="number">1</span>
161
+ <span class="keyword">end</span>
162
+ <span class="keyword">end</span>
163
+
164
+ <span class="ident">puts</span> <span class="ident">count</span>
165
+ <span class="keyword">end</span>
166
+ </pre>
167
+
168
+ <pre class="snippet">
169
+ <span class="shell_command">$ ./count-traces3 traces.warts</span>
170
+ <span class="command_output">1169577966 10.205.150.148 17</span>
171
+ <span class="command_output">1169577964 10.198.133.11 18</span>
172
+ <span class="command_output">2</span>
173
+ </pre>
174
+
175
+ <p>
176
+ It doesn't take much additional code to turn the above script into the
177
+ beginnings of a full-featured trace statistics script; for example:
178
+ </p>
179
+
180
+ <!-- 4. stat-traces ====================================================== -->
181
+ <pre class="ruby snippet">
182
+ <span class="ident">num_traces</span> <span class="punct">=</span> <span class="number">0</span>
183
+ <span class="ident">num_responding</span> <span class="punct">=</span> <span class="number">0</span>
184
+ <span class="ident">stop_reason</span> <span class="punct">=</span> <span class="constant">Hash</span><span class="punct">.</span><span class="ident">new</span> <span class="number">0</span>
185
+ <span class="ident">hop_histogram</span> <span class="punct">=</span> <span class="constant">Hash</span><span class="punct">.</span><span class="ident">new</span> <span class="number">0</span>
186
+
187
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
188
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
189
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
190
+ <span class="ident">num_traces</span> <span class="punct">+=</span> <span class="number">1</span>
191
+ <span class="ident">num_responding</span> <span class="punct">+=</span> <span class="number">1</span> <span class="keyword">if</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dest_responded?</span>
192
+ <span class="ident">stop_reason</span><span class="punct">[</span><span class="ident">trace</span><span class="punct">.</span><span class="ident">stop_reason</span><span class="punct">]</span> <span class="punct">+=</span> <span class="number">1</span>
193
+ <span class="ident">hop_histogram</span><span class="punct">[</span><span class="ident">trace</span><span class="punct">.</span><span class="ident">path_length</span><span class="punct">]</span> <span class="punct">+=</span> <span class="number">1</span>
194
+ <span class="keyword">end</span>
195
+ <span class="keyword">end</span>
196
+
197
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">%8d traces</span><span class="punct">&quot;</span> <span class="punct">%</span> <span class="punct">[</span><span class="ident">num_traces</span><span class="punct">]</span>
198
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">%8d responding</span><span class="punct">&quot;</span> <span class="punct">%</span> <span class="punct">[</span><span class="ident">num_responding</span><span class="punct">]</span>
199
+
200
+ <span class="comment"># from scamper_trace.h:SCAMPER_TRACE_STOP_*</span>
201
+ <span class="ident">stop_text</span> <span class="punct">=</span> <span class="punct">{</span>
202
+ <span class="number">0</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">none (null reason)</span><span class="punct">&quot;,</span>
203
+ <span class="number">1</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">completed (got an ICMP port unreach)</span><span class="punct">&quot;,</span>
204
+ <span class="number">2</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">unreach (got an other ICMP unreach code)</span><span class="punct">&quot;,</span>
205
+ <span class="number">3</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">icmp (got an ICMP msg, not unreach)</span><span class="punct">&quot;,</span>
206
+ <span class="number">4</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">loop (loop detected)</span><span class="punct">&quot;,</span>
207
+ <span class="number">5</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dead (unresponsive target)</span><span class="punct">&quot;,</span>
208
+ <span class="number">6</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">error (sendto error)</span><span class="punct">&quot;</span>
209
+ <span class="punct">}</span>
210
+ <span class="ident">stop_text</span><span class="punct">.</span><span class="ident">default</span> <span class="punct">=</span> <span class="punct">&quot;</span><span class="string">&lt;&lt;UNKNOWN STOP CODE&gt;&gt;</span><span class="punct">&quot;</span>
211
+
212
+ <span class="ident">puts</span>
213
+ <span class="ident">stop_reason</span><span class="punct">.</span><span class="ident">to_a</span><span class="punct">.</span><span class="ident">sort</span><span class="punct">.</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">k</span><span class="punct">,</span> <span class="ident">v</span><span class="punct">|</span>
214
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">%8d stop reason %d, %s</span><span class="punct">&quot;</span> <span class="punct">%</span> <span class="punct">[</span><span class="ident">v</span><span class="punct">,</span> <span class="ident">k</span><span class="punct">,</span> <span class="ident">stop_text</span><span class="punct">[</span><span class="ident">k</span><span class="punct">]]</span>
215
+ <span class="keyword">end</span>
216
+
217
+ <span class="ident">puts</span>
218
+ <span class="ident">hop_histogram</span><span class="punct">.</span><span class="ident">to_a</span><span class="punct">.</span><span class="ident">sort</span><span class="punct">.</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">k</span><span class="punct">,</span> <span class="ident">v</span><span class="punct">|</span>
219
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">%8d %d hops</span><span class="punct">&quot;</span> <span class="punct">%</span> <span class="punct">[</span><span class="ident">v</span><span class="punct">,</span> <span class="ident">k</span><span class="punct">]</span>
220
+ <span class="keyword">end</span>
221
+ </pre>
222
+
223
+ <pre class="snippet">
224
+ <span class="shell_command">$ ./stat-traces traces.warts</span>
225
+ <span class="command_output"> 49 traces</span>
226
+ <span class="command_output"> 2 responding</span>
227
+ <span class="command_output"></span>
228
+ <span class="command_output"> 2 stop reason 1, completed (got an ICMP port unreach)</span>
229
+ <span class="command_output"> 13 stop reason 2, unreach (got an other ICMP unreach code)</span>
230
+ <span class="command_output"> 17 stop reason 4, loop (loop detected)</span>
231
+ <span class="command_output"> 17 stop reason 5, dead (unresponsive target)</span>
232
+ <span class="command_output"></span>
233
+ <span class="command_output"> 3 2 hops</span>
234
+ <span class="command_output"> 1 4 hops</span>
235
+ <span class="command_output"> 1 6 hops</span>
236
+ <span class="command_output"> 11 7 hops</span>
237
+ <span class="command_output"> 5 8 hops</span>
238
+ <span class="command_output"> 2 9 hops</span>
239
+ <span class="command_output"> 1 10 hops</span>
240
+ <span class="command_output"> ...</span>
241
+ </pre>
242
+
243
+ <h2><a name="hop_attributes"></a>Accessing Hop Attributes</h2>
244
+
245
+ <p>
246
+ You access information about a hop via the <code>Warts::Trace</code>
247
+ object returned by <code>Warts::File#read</code>. (Note: There isn't a
248
+ separate class for trace hops, unlike in the underlying <i>scamper</i>
249
+ implementation).
250
+ </p>
251
+
252
+ <p>
253
+ Each accessor method for hop data is named with a <code>hop_</code> prefix;
254
+ for example, <code>hop_addr</code> to obtain the IP address of a hop,
255
+ and <code>hop_rtt</code> to obtain the RTT. You pass an index to these
256
+ hop accessor methods to indicate which hop to examine. For example,
257
+ <code>trace.hop_addr(0)</code> returns the address of the first hop (using
258
+ zero-based indexing).
259
+ </p>
260
+
261
+ <p>
262
+ If <i>scamper</i> did not receive a response at a given hop, then no hop
263
+ data will be available in the trace object at that hop, and all of the hop
264
+ accessor methods will return <code>nil</code> for that hop. (The accessor
265
+ methods will also return <code>nil</code> if the index you provide exceeds
266
+ the highest available hop.) You can also use the
267
+ method <code>Warts::Trace#hop_exists?</code> to determine whether there is
268
+ any hop data at a given index.
269
+ </p>
270
+
271
+ <p>
272
+ Use the method <code>Warts::Trace#hop_count</code> to determine the upper
273
+ bound on the hop indexes; in particular, all valid hop indexes must be
274
+ strictly less than this value. However, you shouldn't ascribe too much
275
+ meaning to <code>hop_count</code>. This value is not necessarily equal to
276
+ the path length (you should use <code>Warts::Trace#path_length</code> to
277
+ compute that) because of possible unresponsive hops at the end of a trace.
278
+ This also means that there may be missing hop data at indexes leading up
279
+ to <code>hop_count</code>.
280
+ </p>
281
+
282
+ <p>
283
+ The following script prints out the IP path of each trace using hop
284
+ accessor methods.
285
+ </p>
286
+
287
+ <!-- 5. hop-addr ========================================================= -->
288
+ <pre class="ruby snippet">
289
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
290
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
291
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
292
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">trace to </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dst</span>
293
+ <span class="punct">(</span><span class="number">0</span> <span class="punct">...</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">hop_count</span><span class="punct">).</span><span class="ident">each</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">i</span><span class="punct">|</span>
294
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> <span class="expr">#{i+1}</span> </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="punct">(</span><span class="ident">trace</span><span class="punct">.</span><span class="ident">hop_addr</span><span class="punct">(</span><span class="ident">i</span><span class="punct">)</span> <span class="punct">||</span> <span class="punct">&quot;</span><span class="string">*</span><span class="punct">&quot;)</span>
295
+ <span class="keyword">end</span>
296
+ <span class="keyword">end</span>
297
+ <span class="keyword">end</span>
298
+ </pre>
299
+
300
+ <pre class="snippet">
301
+ <span class="shell_command">$ hop-addr traces.warts</span>
302
+ <span class="command_output">trace to 10.72.146.120</span>
303
+ <span class="command_output"> 1 10.172.226.1</span>
304
+ <span class="command_output"> 2 10.17.46.8</span>
305
+ <span class="command_output"> 3 10.164.24.205</span>
306
+ <span class="command_output"> 4 10.71.128.5</span>
307
+ <span class="command_output"> 5 10.68.102.97</span>
308
+ <span class="command_output"> 6 10.68.128.157</span>
309
+ <span class="command_output"> 7 10.68.121.194</span>
310
+ <span class="command_output"> 8 10.68.110.162</span>
311
+ <span class="command_output"> 9 10.171.214.137</span>
312
+ <span class="command_output"> 10 *</span>
313
+ <span class="command_output"> 11 10.171.14.170</span>
314
+ <span class="command_output"> 12 10.115.84.234</span>
315
+ <span class="command_output">trace to 10.252.182.175</span>
316
+ <span class="command_output"> 1 10.172.226.1</span>
317
+ <span class="command_output"> 2 10.17.46.8</span>
318
+ <span class="command_output"> 3 10.164.24.157</span>
319
+ <span class="command_output"> 4 10.164.22.231</span>
320
+ <span class="command_output"> 5 *</span>
321
+ <span class="command_output"> 6 *</span>
322
+ <span class="command_output"> 7 *</span>
323
+ <span class="command_output"> 8 *</span>
324
+ <span class="command_output"> 9 *</span>
325
+ <span class="command_output">trace to 10.98.198.154</span>
326
+ <span class="command_output"> ...</span>
327
+ </pre>
328
+
329
+ <p>
330
+ In the second trace above, there are five consecutive unresponsive hops
331
+ at the end of the trace. Therefore, <code>Trace#path_length</code>
332
+ will return 4, while <code>Trace#hop_count</code> will return 9.
333
+ As you can see, <code>path_length</code> indicates the highest
334
+ <b>responding</b> hop, while <code>hop_count</code> indicates the
335
+ highest <b>attempted</b> hop.
336
+ </p>
337
+
338
+ <p>
339
+ <code>Warts::Trace#each_hop</code> provides a more succinct way of
340
+ iterating over all hops and, at the same time, getting an indication of hop
341
+ existence, as demonstrated in the following script:
342
+ </p>
343
+
344
+ <!-- 6. hop-addr2 ======================================================== -->
345
+ <pre class="ruby snippet">
346
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
347
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
348
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
349
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">trace to </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dst</span>
350
+ <span class="ident">trace</span><span class="punct">.</span><span class="ident">each_hop</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">i</span><span class="punct">,</span> <span class="ident">exists</span><span class="punct">|</span>
351
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> <span class="expr">#{i+1}</span> </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="punct">(</span><span class="ident">exists</span> <span class="punct">?</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">hop_addr</span><span class="punct">(</span><span class="ident">i</span><span class="punct">)</span> <span class="punct">:</span> <span class="punct">&quot;</span><span class="string">*</span><span class="punct">&quot;)</span>
352
+ <span class="keyword">end</span>
353
+ <span class="keyword">end</span>
354
+ <span class="keyword">end</span>
355
+ </pre>
356
+
357
+ <h3>Multiple Hop Responses</h3>
358
+
359
+ <p>
360
+ All sample scripts so far have assumed that a hop can only have one
361
+ response, if it has a response at all. This is the case most of the time,
362
+ and making this assumption simplifies the analysis with usually only a
363
+ slight loss of information. However, <i>scamper</i> may store as many
364
+ as <i>N</i> different responses at a given hop, depending on <i>scamper</i>
365
+ settings and the responsiveness of intermediate hops during probing. With
366
+ the default settings, <i>scamper</i> makes up to 2 attempts per hop; that
367
+ is, if the first probe to a hop doesn't elicit a response within some
368
+ timeout period, then <i>scamper</i> will send out a second probe. As a
369
+ result, a hop can have 0, 1, or 2 recorded responses, although the case of
370
+ 2 recorded responses will only happen under a rare scenario--namely, when
371
+ the response to the first attempt is delayed and arrives after the second
372
+ attempt is made. Of course, if you increase the setting for the maximum
373
+ number of attempts per hop, then the chance of getting multiple responses
374
+ at a hop will also increase.
375
+ </p>
376
+
377
+ <p>
378
+ You are much more likely to encounter multiple responses at a hop if you
379
+ explicitly configure <i>scamper</i> to always try <i>N</i> attempts at each
380
+ hop, regardless of responsiveness, and to store all received responses.
381
+ This is the way that <code>traceroute</code> is normally run, with it
382
+ always making 3 attempts at each hop.
383
+ </p>
384
+
385
+ <p>
386
+ Fortunately, working with multiple responses at a hop is easy. Every hop
387
+ accessor method, like <code>hop_addr</code>, can actually take two
388
+ parameters. The first parameter is the hop index, as you've already seen.
389
+ The second parameter is the <b>response</b> index, beginning with 0 for the
390
+ first response. The response parameter has a default value of 0, which is
391
+ the reason we were able to leave it out in the sample code so far. Hence,
392
+ the call <code>hop_addr(i)</code> is equivalent to <code>hop_addr(i,
393
+ 0)</code>. One way to iterate over all responses at a given hop is to
394
+ use <code>Warts::Trace#each_response</code>, as illustrated by the
395
+ following script, which prints out the IP address of all responses at all
396
+ hops:
397
+ </p>
398
+
399
+ <!-- 7. hop-addr3 ======================================================== -->
400
+ <pre class="ruby snippet">
401
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
402
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
403
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
404
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">trace to </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dst</span>
405
+ <span class="ident">trace</span><span class="punct">.</span><span class="ident">each_hop</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">hop</span><span class="punct">,</span> <span class="ident">exists</span><span class="punct">|</span>
406
+ <span class="ident">print</span> <span class="punct">&quot;</span><span class="string"> <span class="expr">#{hop+1}</span></span><span class="punct">&quot;</span>
407
+ <span class="keyword">if</span> <span class="ident">exists</span>
408
+ <span class="ident">trace</span><span class="punct">.</span><span class="ident">each_response</span><span class="punct">(</span><span class="ident">hop</span><span class="punct">)</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">response</span><span class="punct">|</span>
409
+ <span class="ident">print</span> <span class="punct">&quot;</span><span class="string"> </span><span class="punct">&quot;,</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">hop_addr</span><span class="punct">(</span><span class="ident">hop</span><span class="punct">,</span> <span class="ident">response</span><span class="punct">)</span>
410
+ <span class="keyword">end</span>
411
+ <span class="ident">puts</span>
412
+ <span class="keyword">else</span>
413
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> *</span><span class="punct">&quot;</span>
414
+ <span class="keyword">end</span>
415
+ <span class="keyword">end</span>
416
+ <span class="keyword">end</span>
417
+ <span class="keyword">end</span>
418
+ </pre>
419
+
420
+ <pre class="snippet">
421
+ <span class="shell_command">$ hop-response traces.warts</span>
422
+ <span class="command_output">trace to 10.72.146.120</span>
423
+ <span class="command_output"> 1 10.172.226.1</span>
424
+ <span class="command_output"> 2 10.17.46.8 10.17.46.10</span>
425
+ <span class="command_output"> 3 10.164.24.205 10.164.24.207</span>
426
+ <span class="command_output"> 4 *</span>
427
+ <span class="command_output"> 5 10.68.121.194</span>
428
+ <span class="command_output"> 6 10.72.146.120</span>
429
+ </pre>
430
+
431
+ <p>
432
+ You can iterate over both hops and responses at the same time with
433
+ <code>Warts::Trace#each_hop_and_response</code> (or more simply
434
+ <code>Warts::Trace#each</code>). The following script prints out the
435
+ IP address of all responses of all hops:
436
+ </p>
437
+
438
+ <!-- 8. hop-addr4 ======================================================== -->
439
+ <pre class="ruby snippet">
440
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
441
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
442
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
443
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">trace to </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dst</span>
444
+ <span class="ident">trace</span><span class="punct">.</span><span class="ident">each_hop_and_response</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">hop</span><span class="punct">,</span> <span class="ident">response</span><span class="punct">,</span> <span class="ident">hop_exists</span><span class="punct">|</span>
445
+ <span class="ident">printf</span> <span class="punct">&quot;</span><span class="string"> hop=%d, resp=%d: %s<span class="escape">\n</span></span><span class="punct">&quot;,</span> <span class="ident">hop</span><span class="punct">,</span> <span class="ident">response</span><span class="punct">,</span>
446
+ <span class="punct">(</span><span class="ident">hop_exists</span> <span class="punct">?</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">hop_addr</span><span class="punct">(</span><span class="ident">hop</span><span class="punct">,</span> <span class="ident">response</span><span class="punct">)</span> <span class="punct">:</span> <span class="punct">&quot;</span><span class="string">*</span><span class="punct">&quot;)</span>
447
+ <span class="keyword">end</span>
448
+ <span class="keyword">end</span>
449
+ <span class="keyword">end</span>
450
+ </pre>
451
+
452
+ <pre class="snippet">
453
+ <span class="shell_command">$ hop-response2 traces.warts</span>
454
+ <span class="command_output">trace to 10.72.146.120</span>
455
+ <span class="command_output"> hop=0, resp=0: 10.172.226.1</span>
456
+ <span class="command_output"> hop=1, resp=0: 10.17.46.8</span>
457
+ <span class="command_output"> hop=1, resp=1: 10.17.46.10</span>
458
+ <span class="command_output"> hop=2, resp=0: 10.164.24.205</span>
459
+ <span class="command_output"> hop=2, resp=1: 10.164.24.207</span>
460
+ <span class="command_output"> hop=3, resp=0: *</span>
461
+ <span class="command_output"> hop=4, resp=0: 10.68.121.194</span>
462
+ <span class="command_output"> hop=5, resp=0: 10.72.146.120</span>
463
+ </pre>
464
+
465
+
466
+ <h2><a name="list_attributes"></a>Accessing List Attributes</h2>
467
+
468
+ <p>
469
+ In the terminology of <i>scamper</i>, a <b>list</b> is a set of destination
470
+ addresses. You typically store a list in a file, and give the name of the
471
+ file to <i>scamper</i> on the command line. A list has some logical
472
+ identity, and for the purposes of keeping track of which list a trace
473
+ belongs to, it is helpful to record the list ID number, name, and/or a
474
+ description in a trace file. <i>scamper</i> itself doesn't need or use
475
+ this sort of descriptive information about a list, but it can store this
476
+ information in generated trace files on your behalf.
477
+ </p>
478
+
479
+ <p>
480
+ Given a warts file, you can examine any recorded information about lists in
481
+ one of two ways. The first way is to use the accessor
482
+ method <code>Warts::Trace#list</code> to get information about the list to
483
+ which a particular trace belongs (a warts file can contain traces from more
484
+ than one list, but a given trace can only belong to a single list). The
485
+ list information is returned in the form of a <code>Warts::List</code>
486
+ object, which has accessors for the list ID, name, and description.
487
+ (<code>Warts::List</code> also stores the canonical name of the measurement
488
+ monitor.) For example, the following script prints out the list
489
+ information for the first trace in a warts file:
490
+ </p>
491
+
492
+ <!-- 9. list =========================================================== -->
493
+ <pre class="ruby snippet">
494
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
495
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
496
+ <span class="ident">trace</span> <span class="punct">=</span> <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span>
497
+ <span class="keyword">if</span> <span class="ident">trace</span>
498
+ <span class="ident">list</span> <span class="punct">=</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">list</span>
499
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> id: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">list</span><span class="punct">.</span><span class="ident">id</span><span class="punct">.</span><span class="ident">to_s</span>
500
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> name: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">list</span><span class="punct">.</span><span class="ident">name</span>
501
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> descr: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">list</span><span class="punct">.</span><span class="ident">descr</span>
502
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">monitor: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">list</span><span class="punct">.</span><span class="ident">monitor</span>
503
+ <span class="keyword">end</span>
504
+ <span class="keyword">end</span>
505
+ </pre>
506
+
507
+ <pre class="snippet">
508
+ <span class="shell_command">$ ./list-info traces.warts</span>
509
+ <span class="command_output"> id: 2</span>
510
+ <span class="command_output"> name: allpref24</span>
511
+ <span class="command_output"> descr: One randomly-selected address in every routed /24.</span>
512
+ <span class="command_output">monitor: mnl-ph</span>
513
+ </pre>
514
+
515
+ <p>
516
+ The second way to examine list information is to directly retrieve the
517
+ <code>Warts::List</code> objects stored in a warts file rather than
518
+ accessing them indirectly via a <code>Warts::Trace</code> object. For
519
+ example, the following script examines all list and trace objects in a
520
+ warts file, printing out the details of each encountered list object and
521
+ counting encountered traces (note the
522
+ additional <code>Warts::File::LIST</code> passed
523
+ to <code>File#add_filters</code>):
524
+ </p>
525
+
526
+ <!-- 10. list2 ========================================================== -->
527
+ <pre class="ruby snippet">
528
+ <span class="ident">num_traces</span> <span class="punct">=</span> <span class="number">0</span>
529
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
530
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span><span class="punct">,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">LIST</span>
531
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">element</span><span class="punct">|</span>
532
+ <span class="keyword">case</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span>
533
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
534
+ <span class="ident">num_traces</span> <span class="punct">+=</span> <span class="number">1</span>
535
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">LIST</span>
536
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> id: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">id</span><span class="punct">.</span><span class="ident">to_s</span>
537
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> name: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">name</span>
538
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> descr: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">descr</span>
539
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">monitor: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">monitor</span>
540
+ <span class="keyword">end</span>
541
+ <span class="keyword">end</span>
542
+ <span class="keyword">end</span>
543
+
544
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"># traces: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">num_traces</span><span class="punct">.</span><span class="ident">to_s</span>
545
+ </pre>
546
+
547
+ <pre class="snippet">
548
+ <span class="shell_command">$ ./list-info2 traces.warts</span>
549
+ <span class="command_output"> id: 2</span>
550
+ <span class="command_output"> name: allpref24</span>
551
+ <span class="command_output"> descr: One randomly-selected address in every routed /24.</span>
552
+ <span class="command_output">monitor: mnl-ph</span>
553
+ <span class="command_output"> id: 3</span>
554
+ <span class="command_output"> name: dnssurvey</span>
555
+ <span class="command_output"> descr: Top 500 DNS servers.</span>
556
+ <span class="command_output">monitor: mnl-ph</span>
557
+ <span class="command_output"># traces: 17496</span>
558
+ </pre>
559
+
560
+
561
+ <h2><a name="cycle_attributes"></a>Accessing Cycle Attributes</h2>
562
+
563
+ <p>
564
+ In the terminology of <i>scamper</i>, a <b>cycle</b> is a single pass
565
+ through a destination list. A single warts file can contain multiple
566
+ cycles of data.
567
+ </p>
568
+
569
+ <p>
570
+ Just as for list information, there are two ways of getting at cycle
571
+ information stored in a warts file. The first way is to use the accessor
572
+ method <code>Warts::Trace#cycle</code> to get information about the cycle
573
+ in which a trace was collected. The cycle information is returned in the
574
+ form of a <code>Warts::Cycle</code> object, which has accessors for the
575
+ cycle ID, start time, and stop time. (<code>Warts::Cycle</code> also
576
+ stores the hostname of the measurement monitor at the start of the cycle,
577
+ and you can get the associated list with <code>Warts::Cycle#list</code>.)
578
+ For example, the following script prints out the cycle information for the
579
+ first trace in a warts file:
580
+ </p>
581
+
582
+ <!-- 11. cycle ========================================================== -->
583
+ <pre class="ruby snippet">
584
+ <span class="keyword">def </span><span class="method">t</span><span class="punct">(</span><span class="ident">timestamp</span><span class="punct">)</span>
585
+ <span class="ident">timestamp</span><span class="punct">.</span><span class="ident">to_s</span> <span class="punct">+</span> <span class="punct">&quot;</span><span class="string"> (</span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">at</span><span class="punct">(</span><span class="ident">timestamp</span><span class="punct">).</span><span class="ident">to_s</span> <span class="punct">+</span> <span class="punct">&quot;</span><span class="string">)</span><span class="punct">&quot;</span>
586
+ <span class="keyword">end</span>
587
+
588
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
589
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
590
+ <span class="ident">trace</span> <span class="punct">=</span> <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span>
591
+ <span class="keyword">if</span> <span class="ident">trace</span>
592
+ <span class="ident">cycle</span> <span class="punct">=</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">cycle</span>
593
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> id: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">cycle</span><span class="punct">.</span><span class="ident">id</span><span class="punct">.</span><span class="ident">to_s</span>
594
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">start_time: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">t</span><span class="punct">(</span><span class="ident">cycle</span><span class="punct">.</span><span class="ident">start_time</span><span class="punct">)</span>
595
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> stop_time: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">t</span><span class="punct">(</span><span class="ident">cycle</span><span class="punct">.</span><span class="ident">stop_time</span><span class="punct">)</span>
596
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> hostname: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">cycle</span><span class="punct">.</span><span class="ident">hostname</span>
597
+ <span class="keyword">end</span>
598
+ <span class="keyword">end</span>
599
+ </pre>
600
+
601
+ <p>
602
+ The second way to examine cycle information is to directly retrieve
603
+ the <code>Warts::Cycle</code> objects stored in a warts file rather than
604
+ accessing them indirectly via a <code>Warts::Trace</code> object. There
605
+ are actually three types of cycle objects: cycle <b>start</b>, cycle
606
+ <b>stop</b>, and cycle <b>def</b>. However, all three types of objects are
607
+ represented with the same class. You can determine the cycle type
608
+ with <code>Warts::Cycle#element_type</code>.
609
+ </p>
610
+
611
+ <p>
612
+ <i>scamper</i> writes out cycle-start and cycle-stop records at the
613
+ beginning and end of a cycle, as you would expect. <i>scamper</i> writes
614
+ out a cycle-def record only when needed and only when the traces in a cycle
615
+ are stored across multiple files. The following figure should help clarify
616
+ the role of cycle-def records. Because the traces of the second cycle
617
+ spill over from <code>trace1.warts</code>
618
+ to <code>trace2.warts</code>, <i>scamper</i> writes out a cycle-def record
619
+ at the beginning of the latter file.
620
+ </p>
621
+
622
+ <pre>
623
+ +====================+
624
+ | cycle <span class="fig_green">start</span> record | <span class="fig_blue">trace1.warts</span>
625
+ +--------------------+
626
+ | trace 1 |
627
+ | trace 2 |
628
+ | ... |
629
+ | trace n |
630
+ +--------------------+
631
+ | cycle <span class="fig_green">stop</span> record |
632
+ +--------------------+
633
+ | cycle <span class="fig_green">start</span> record |
634
+ +--------------------+
635
+ | trace 1 |
636
+ | trace 2 |
637
+ | ... |
638
+ | trace k < n |
639
+ +====================+
640
+
641
+ +====================+
642
+ | cycle <span class="fig_red">def</span> record | <span class="fig_blue">trace2.warts</span>
643
+ +--------------------+
644
+ | trace k + 1 |
645
+ | trace k + 2 |
646
+ | ... |
647
+ | trace n |
648
+ +--------------------+
649
+ | cycle <span class="fig_green">stop</span> record |
650
+ +====================+
651
+ </pre>
652
+
653
+ <p>
654
+ The following script examines all cycle and trace objects in a warts file,
655
+ printing out the details of each encountered cycle object and counting
656
+ encountered traces (note the additional <code>Warts::File::CYCLE_xxx</code>
657
+ values passed to <code>File#add_filters</code>):
658
+ </p>
659
+
660
+ <!-- 12. cycle2 ========================================================== -->
661
+ <pre class="ruby snippet">
662
+ <span class="constant">CYCLE_TYPE</span> <span class="punct">=</span> <span class="punct">{</span>
663
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_START</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">start</span><span class="punct">&quot;,</span>
664
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">stop</span><span class="punct">&quot;,</span>
665
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_DEF</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">def</span><span class="punct">&quot;</span>
666
+ <span class="punct">}</span>
667
+
668
+ <span class="keyword">def </span><span class="method">t</span><span class="punct">(</span><span class="ident">timestamp</span><span class="punct">)</span>
669
+ <span class="ident">timestamp</span><span class="punct">.</span><span class="ident">to_s</span> <span class="punct">+</span> <span class="punct">&quot;</span><span class="string"> (</span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="constant">Time</span><span class="punct">.</span><span class="ident">at</span><span class="punct">(</span><span class="ident">timestamp</span><span class="punct">).</span><span class="ident">to_s</span> <span class="punct">+</span> <span class="punct">&quot;</span><span class="string">)</span><span class="punct">&quot;</span>
670
+ <span class="keyword">end</span>
671
+
672
+ <span class="ident">num_traces</span> <span class="punct">=</span> <span class="number">0</span>
673
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
674
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span><span class="punct">,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_START</span><span class="punct">,</span>
675
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span><span class="punct">,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_DEF</span>
676
+
677
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">element</span><span class="punct">|</span>
678
+ <span class="keyword">case</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span>
679
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
680
+ <span class="ident">num_traces</span> <span class="punct">+=</span> <span class="number">1</span>
681
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_START</span><span class="punct">,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span><span class="punct">,</span>
682
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_DEF</span>
683
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"><span class="escape">\n</span>===&gt; cycle </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="constant">CYCLE_TYPE</span><span class="punct">[</span><span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span><span class="punct">]</span>
684
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> id: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">id</span><span class="punct">.</span><span class="ident">to_s</span>
685
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string">start_time: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">t</span><span class="punct">(</span><span class="ident">element</span><span class="punct">.</span><span class="ident">start_time</span><span class="punct">)</span>
686
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> stop_time: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">t</span><span class="punct">(</span><span class="ident">element</span><span class="punct">.</span><span class="ident">stop_time</span><span class="punct">)</span>
687
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"> hostname: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">hostname</span>
688
+ <span class="keyword">end</span>
689
+ <span class="keyword">end</span>
690
+ <span class="keyword">end</span>
691
+
692
+ <span class="ident">puts</span> <span class="punct">&quot;</span><span class="string"># traces: </span><span class="punct">&quot;</span> <span class="punct">+</span> <span class="ident">num_traces</span><span class="punct">.</span><span class="ident">to_s</span>
693
+ </pre>
694
+
695
+
696
+ <pre class="snippet">
697
+ <span class="shell_command">$ ./cycle-info2 traces.warts</span>
698
+ <span class="command_output"></span>
699
+ <span class="command_output">===> cycle start</span>
700
+ <span class="command_output"> id: 28</span>
701
+ <span class="command_output">start_time: 1190158509 (Tue Sep 18 16:35:09 -0700 2007)</span>
702
+ <span class="command_output"> stop_time: 0 (Wed Dec 31 16:00:00 -0800 1969)</span>
703
+ <span class="command_output"> hostname: mnl-ph.ark.caida.org</span>
704
+ <span class="command_output"></span>
705
+ <span class="command_output">===> cycle stop</span>
706
+ <span class="command_output"> id: 28</span>
707
+ <span class="command_output">start_time: 1190158509 (Tue Sep 18 16:35:09 -0700 2007)</span>
708
+ <span class="command_output"> stop_time: 1190159039 (Tue Sep 18 16:43:59 -0700 2007)</span>
709
+ <span class="command_output"> hostname: mnl-ph.ark.caida.org</span>
710
+ <span class="command_output"># traces: 17496</span>
711
+ </pre>
712
+
713
+ <p>
714
+ <b>NOTE:</b> Warts files produced by
715
+ the <a href="http://www.caida.org/projects/ark/">Archipelago
716
+ Measurement Infrastructure</a> (Ark) don't have cycle start or stop
717
+ records. They only contain cycle def records, and there may be more
718
+ than one cycle def record per file. This happens because Ark
719
+ reorganizes raw scamper traces into hourly and daily files, and the
720
+ current implementation of the reorganization procedure doesn't
721
+ preserve cycle start/stop records. However, if you
722
+ use <i>rb-wartslib</i> to process scamper traces you've collected
723
+ yourself, then you will see cycle start, stop, and def records in the
724
+ manner described above.
725
+ </p>
726
+
727
+ <h2><a name="writing_files"></a>Writing Files</h2>
728
+
729
+ <p>
730
+ You can write new warts files with this library. This ability is useful
731
+ for filtering out traces and for re-organizing traces into a different set
732
+ of files (for example, into daily files). Please note, however, that you
733
+ can't create completely new traces in memory--that is, you can only write
734
+ out traces you've read in from another file.
735
+ </p>
736
+
737
+ <p>
738
+ For example, the following script writes a new file <code>out.warts</code>
739
+ containing only the traces in the input file that have both a responding
740
+ destination and a path length greater than 5:
741
+ </p>
742
+
743
+ <!-- 13. write ========================================================== -->
744
+ <pre class="ruby snippet">
745
+ <span class="ident">out</span> <span class="punct">=</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span> <span class="punct">&quot;</span><span class="string">out.warts</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">w</span><span class="punct">&quot;</span>
746
+
747
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
748
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
749
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
750
+ <span class="keyword">if</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">dest_responded?</span> <span class="punct">&amp;&amp;</span> <span class="ident">trace</span><span class="punct">.</span><span class="ident">path_length</span> <span class="punct">&gt;</span> <span class="number">5</span>
751
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">write</span> <span class="ident">trace</span>
752
+ <span class="keyword">end</span>
753
+ <span class="keyword">end</span>
754
+ <span class="keyword">end</span>
755
+
756
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">close</span>
757
+ </pre>
758
+
759
+ <p>
760
+ When you write out a trace object, the associated list and cycle objects
761
+ are written out automatically, which is the reason why the above script is
762
+ so simple. However, only a cycle-def object is written out automatically,
763
+ so information about the cycle end time will be missing in the output file
764
+ (a cycle-def object has the start time so the lack of a cycle-start object
765
+ isn't a real problem). If all you want to do is analyze trace data, then
766
+ having only the cycle-def object should be fine. It's easy enough, though,
767
+ to write out the cycle start and end objects yourself if you need them, as
768
+ in the following script:
769
+ </p>
770
+
771
+ <!-- 14. write2 ========================================================== -->
772
+ <pre class="ruby snippet">
773
+ <span class="ident">out</span> <span class="punct">=</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span> <span class="punct">&quot;</span><span class="string">out.warts</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">w</span><span class="punct">&quot;</span>
774
+
775
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
776
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span><span class="punct">,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_START</span><span class="punct">,</span>
777
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span>
778
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">element</span><span class="punct">|</span>
779
+ <span class="keyword">if</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span> <span class="punct">==</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
780
+ <span class="keyword">if</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">dest_responded?</span> <span class="punct">&amp;&amp;</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">path_length</span> <span class="punct">&gt;</span> <span class="number">5</span>
781
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">write</span> <span class="ident">element</span>
782
+ <span class="keyword">end</span>
783
+ <span class="keyword">else</span>
784
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">write</span> <span class="ident">element</span>
785
+ <span class="keyword">end</span>
786
+ <span class="keyword">end</span>
787
+ <span class="keyword">end</span>
788
+
789
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">close</span>
790
+ </pre>
791
+
792
+ <p>
793
+ By default, files are written in the warts format. You can also write out
794
+ files in the traditional textual traceroute format, as illustrated by the
795
+ following script:
796
+ </p>
797
+
798
+ <!-- 15. write3 ========================================================== -->
799
+ <pre class="ruby snippet">
800
+ <span class="ident">out</span> <span class="punct">=</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span> <span class="punct">&quot;</span><span class="string">out.txt</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">w</span><span class="punct">&quot;,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACEROUTE</span>
801
+
802
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
803
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
804
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
805
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">write</span> <span class="ident">trace</span>
806
+ <span class="keyword">end</span>
807
+ <span class="keyword">end</span>
808
+
809
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">close</span>
810
+ </pre>
811
+
812
+
813
+ <pre class="snippet">
814
+ <span class="shell_command">$ ./trace-txt traces.warts</span>
815
+ <span class="shell_command">$ cat out.txt</span>
816
+ <span class="command_output">traceroute from 10.172.226.88 to 10.58.204.93</spa
817
+ n>
818
+ <span class="command_output"> 1 10.172.226.1 0.789 ms</span>
819
+ <span class="command_output"> 2 10.17.46.8 40.779 ms !N</span>
820
+ <span class="command_output">traceroute from 10.172.226.88 to 10.237.229.96</sp
821
+ an>
822
+ <span class="command_output"> 1 10.172.226.1 0.805 ms</span>
823
+ <span class="command_output"> 2 10.17.46.8 33.306 ms</span>
824
+ <span class="command_output"> 3 10.164.24.205 5.271 ms</span>
825
+ <span class="command_output"> 4 10.71.128.5 5.371 ms</span>
826
+ <span class="command_output"> 5 10.68.102.190 5.841 ms</span>
827
+ <span class="command_output"> 6 10.69.132.9 16.056 ms</span>
828
+ <span class="command_output"> 7 10.69.132.9 13.406 ms</span>
829
+ </pre>
830
+
831
+
832
+ <p>
833
+ The examples so far have opened files by path. You can also read/write
834
+ files that are already open by passing either an <code>IO</code> object
835
+ (and by extension anything that derives from <code>IO</code> like files,
836
+ pipes, and sockets) or a numeric file descriptor (a la Unix). For example,
837
+ the following script prints a warts file to stdout in the textual
838
+ traceroute format:
839
+ </p>
840
+
841
+ <!-- 16. write4 ========================================================== -->
842
+ <pre class="ruby snippet">
843
+ <span class="ident">out</span> <span class="punct">=</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span> <span class="global">$stdout</span><span class="punct">,</span> <span class="punct">&quot;</span><span class="string">w</span><span class="punct">&quot;,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACEROUTE</span>
844
+
845
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
846
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_filters</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
847
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">trace</span><span class="punct">|</span>
848
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">write</span> <span class="ident">trace</span>
849
+ <span class="keyword">end</span>
850
+ <span class="keyword">end</span>
851
+ </pre>
852
+
853
+
854
+ <h2><a name="modifying_data"></a>Modifying Lists and Cycles</h2>
855
+
856
+ <p>
857
+ Traces read in with this library are immutable, but you can modify the
858
+ associated list and cycle objects and write out modified versions to files.
859
+ This ability to modify lists and cycles is supported primarily to enable
860
+ easy re-organization of traces into a different set of files.
861
+ </p>
862
+
863
+ <p>
864
+ We say <i>modify</i> as a simplifying fiction, because in truth, list and
865
+ cycle objects are as equally immutable as traces. To <i>modify</i> lists
866
+ and cycles, you <b>derive</b> a new object with updated values from an
867
+ existing object (the old object is unmodified). Then you assign the new
868
+ object to a trace, thereby replacing the association with the old object.
869
+ For example, the following script changes the ID and hostname of cycles
870
+ to <code>5</code> and <code>foo.bar.com</code>, respectivey, and updates
871
+ traces to use the new cycle objects (note: cycle start and def objects will
872
+ always be read in before any traces that use those cycle objects):
873
+ </p>
874
+
875
+ <!-- 17. modify ========================================================== -->
876
+ <pre class="ruby snippet">
877
+ <span class="ident">out</span> <span class="punct">=</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span> <span class="punct">&quot;</span><span class="string">out.warts</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">w</span><span class="punct">&quot;</span>
878
+
879
+ <span class="ident">cycle</span> <span class="punct">=</span> <span class="constant">nil</span>
880
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
881
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_all_filters</span>
882
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">element</span><span class="punct">|</span>
883
+ <span class="keyword">case</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span>
884
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
885
+ <span class="ident">element</span><span class="punct">.</span><span class="ident">cycle</span> <span class="punct">=</span> <span class="ident">cycle</span>
886
+
887
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_START</span><span class="punct">,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_DEF</span><span class="punct">,</span>
888
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span>
889
+ <span class="ident">element</span> <span class="punct">=</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">derive</span><span class="punct">(</span><span class="symbol">:id</span> <span class="punct">=&gt;</span> <span class="number">5</span><span class="punct">,</span> <span class="symbol">:hostname</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">foo.bar.com</span><span class="punct">&quot;)</span>
890
+ <span class="keyword">unless</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span> <span class="punct">==</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span>
891
+ <span class="ident">cycle</span> <span class="punct">=</span> <span class="ident">element</span>
892
+ <span class="keyword">end</span>
893
+ <span class="keyword">end</span>
894
+
895
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">write</span> <span class="ident">element</span>
896
+ <span class="keyword">end</span>
897
+ <span class="keyword">end</span>
898
+
899
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">close</span>
900
+ </pre>
901
+
902
+
903
+ <p>
904
+ You would follow the same basic procedure to modify lists. Note that you
905
+ can't directly assign a list to a trace object; you must update the list in
906
+ a cycle and then assign the cycle to a trace. For example, the following
907
+ script changes the name of lists to <code>dnssurvey</code> (and changes
908
+ the ID of cycles to 5):
909
+ </p>
910
+
911
+ <!-- 18. modify2 ========================================================= -->
912
+ <pre class="ruby snippet">
913
+ <span class="ident">out</span> <span class="punct">=</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="ident">open</span> <span class="punct">&quot;</span><span class="string">out.warts</span><span class="punct">&quot;,</span> <span class="punct">&quot;</span><span class="string">w</span><span class="punct">&quot;</span>
914
+
915
+ <span class="ident">cycle</span> <span class="punct">=</span> <span class="constant">nil</span>
916
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">.</span><span class="ident">open</span><span class="punct">(</span><span class="constant">ARGV</span><span class="punct">[</span><span class="number">0</span><span class="punct">])</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">file</span><span class="punct">|</span>
917
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">add_all_filters</span>
918
+ <span class="ident">file</span><span class="punct">.</span><span class="ident">read</span> <span class="keyword">do</span> <span class="punct">|</span><span class="ident">element</span><span class="punct">|</span>
919
+ <span class="keyword">case</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span>
920
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">TRACE</span>
921
+ <span class="ident">element</span><span class="punct">.</span><span class="ident">cycle</span> <span class="punct">=</span> <span class="ident">cycle</span>
922
+
923
+ <span class="keyword">when</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_START</span><span class="punct">,</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_DEF</span><span class="punct">,</span>
924
+ <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span>
925
+ <span class="ident">list</span> <span class="punct">=</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">list</span><span class="punct">.</span><span class="ident">derive</span><span class="punct">(</span><span class="symbol">:name</span> <span class="punct">=&gt;</span> <span class="punct">&quot;</span><span class="string">dnssurvey</span><span class="punct">&quot;)</span>
926
+ <span class="ident">element</span> <span class="punct">=</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">derive</span><span class="punct">(</span><span class="symbol">:id</span> <span class="punct">=&gt;</span> <span class="number">5</span><span class="punct">,</span> <span class="symbol">:list</span> <span class="punct">=&gt;</span> <span class="ident">list</span><span class="punct">)</span>
927
+ <span class="keyword">unless</span> <span class="ident">element</span><span class="punct">.</span><span class="ident">element_type</span> <span class="punct">==</span> <span class="constant">Warts</span><span class="punct">::</span><span class="constant">File</span><span class="punct">::</span><span class="constant">CYCLE_STOP</span>
928
+ <span class="ident">cycle</span> <span class="punct">=</span> <span class="ident">element</span>
929
+ <span class="keyword">end</span>
930
+ <span class="keyword">end</span>
931
+
932
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">write</span> <span class="ident">element</span>
933
+ <span class="keyword">end</span>
934
+ <span class="keyword">end</span>
935
+
936
+ <span class="ident">out</span><span class="punct">.</span><span class="ident">close</span>
937
+ </pre>
938
+
939
+
940
+ <h2>Further Reading</h2>
941
+
942
+ <p>
943
+ This concludes the tutorial. There are more features in the library than
944
+ described so far. Browse the <a href="reference.html">class reference</a>
945
+ and <a href="samples.html">sample scripts</a> for details.
946
+ </p>
947
+
948
+ <!---->
949
+ </div></div>
950
+ </body></html>