scriptroute 0.4.14

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml ADDED
@@ -0,0 +1,7 @@
1
+ ---
2
+ SHA1:
3
+ metadata.gz: 3d192161acfbf508dfd7d953bc7ec1a219930d15
4
+ data.tar.gz: a3c7cbd73442f9aa4cc263830a71b62023f08355
5
+ SHA512:
6
+ metadata.gz: 3a98db9cec4c8d90da6c8958e68d063d3049c68d88ac612184abfef44a789f8b57120b2325625f3704c770db3a6557aa2ad6336d36655be28067426b0fff69f0
7
+ data.tar.gz: 77be1bb191576fa8890c8395c1d93577e060cfe4a846989c74c51ae24797e3dbf1c78f091dbedc33ef72c3aa78c373ba391cfe1ee1eed3dd88c70815dee82425
data/bin/sr-ally ADDED
@@ -0,0 +1,21 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'scriptroute/ally'
4
+ require 'scriptroute/ipaddr4'
5
+
6
+ if(ARGV.length < 2) then
7
+ puts "ERROR: need two ip addresses to compare."
8
+ exit 3;
9
+ end
10
+
11
+ verdict = Ally.new(ARGV[0], ARGV[1]);
12
+ puts verdict
13
+ exit case verdict.to_s
14
+ when /^ALIAS/
15
+ 0;
16
+ when /^NOT ALIAS/
17
+ 1;
18
+ when /^UNKNOWN/
19
+ 2;
20
+ end
21
+
data/bin/sr-liveness ADDED
@@ -0,0 +1,11 @@
1
+ #!/usr/bin/env ruby
2
+
3
+ require 'scriptroute'
4
+ require 'scriptroute/liveness'
5
+
6
+ if ARGV.empty? then
7
+ puts "give me hosts to ping"
8
+ end
9
+ Scriptroute::daemon_running_or_exit
10
+ puts Scriptroute::LivenessTest.new(ARGV)
11
+
data/bin/sr-ping-T ADDED
@@ -0,0 +1,69 @@
1
+ #!/usr/bin/env ruby
2
+ # -*- mode: Ruby -*-
3
+
4
+ require 'scriptroute'
5
+ require 'scriptroute/packets'
6
+ require 'scriptroute/nameify'
7
+
8
+ $have_socket = begin
9
+ require 'socket'
10
+ true
11
+ rescue
12
+ false
13
+ end
14
+
15
+ Scriptroute::daemon_running_or_exit
16
+
17
+ i = Scriptroute::ICMPecho.new(0)
18
+ # i.ip_dst = 0x805f0218 # poplar
19
+ i.ip_dst = Scriptroute::dns_lookup(ARGV[0])
20
+ # i.ip_dst = 0xc6ca4b65 # www.sdsc.edu
21
+ # rr = RecordRoute_option.new
22
+ # IPOPT_TS_TSONLY = 0
23
+ # IPOPT_TS_TSANDADDR = 1
24
+ # IPOPT_TS_PRESPEC = 3
25
+ rr = Scriptroute::Timestamp_option.new(Scriptroute::IPv4option::IPOPT_TS_TSONLY)
26
+ i.ip_ttl=15
27
+ i.add_option(rr)
28
+
29
+ p = Scriptroute::send_train([ Struct::DelayedPacket.new(0, i) ])
30
+
31
+ # p[0].response.packet.to_bytes.each_byte { |b| puts "%x " % b }
32
+
33
+ if (p[0].response != nil) then
34
+ if ($VERBOSE) then puts p[0].response.packet end
35
+ resp = ""
36
+ begin
37
+ resp = Scriptroute::IPv4.creator(p[0].response.packet.to_bytes)
38
+ resp.ip_options.each { |opt|
39
+ if(opt.is_a?(Scriptroute::Timestamp_option)) then
40
+ if(resp.ip_options[0].routers != nil &&
41
+ resp.ip_options[0].times != nil && resp.ip_options[0].times.length > 0) then
42
+ opt.times.each_index { |i|
43
+ puts Scriptroute.nameify(resp.ip_options[0].routers[i]) + " " + resp.ip_options[0].times[i].to_s
44
+ }
45
+ else
46
+ opt.times.each_index { |i|
47
+ puts resp.ip_options[0].times[i].to_s
48
+ }
49
+ end
50
+ elsif(opt.is_a?(Scriptroute::RecordRoute_option)) then
51
+ opt.routers.each_index { |i|
52
+ puts "%d %s" % [ i+1, Scriptroute.nameify(resp.ip_options[0].routers[i]) ]
53
+ }
54
+ else
55
+ raise "unknown option class %s" % opt.class.to_s
56
+ end
57
+ }
58
+ rescue => e
59
+ puts "failed due to #{e} parsing: #{resp}"
60
+ end
61
+ else
62
+ puts "no response to ping -r from %s" % p[0].probe.packet.ip_dst
63
+ end
64
+
65
+ # .map { |a|
66
+ # a
67
+ #nameify(a)
68
+ #}
69
+
@@ -0,0 +1,51 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'scriptroute'
4
+ require 'scriptroute/rockettrace'
5
+ require 'scriptroute/nameify'
6
+ require 'scriptroute/commando'
7
+
8
+ c = Commando.new(ARGV, # allows substitution by srclient.rb
9
+ [ CommandoVar.new( [ "-S", "--start-ttl" ],
10
+ "hops out to start" ,
11
+ :$StartTTL, 1),
12
+ CommandoVar.new( [ "-n", "--numeric" ],
13
+ "do no hostname lookup or interpretation" ,
14
+ :$Numeric, false),
15
+ CommandoVar.new( [ "-q", "--queries" ],
16
+ "number of probes at each ttl" ,
17
+ :$Repetitions, 3),
18
+ # todo CommandoVar.new( "--use-icmp",
19
+ # todo "use icmp probes instead of udp" ,
20
+ # todo :$UseICMP, false ) ],
21
+ CommandoVar.new( [ "-o", "--output" ],
22
+ "file to use instead of stdout" ,
23
+ :$Output, ""),
24
+ CommandoVar.new( "--use-tcp",
25
+ "use tcp probes instead of udp" ,
26
+ :$UseTCP, false ) ],
27
+ "destination-host")
28
+
29
+ raise "must start with a positive ttl" if($StartTTL <= 0)
30
+ if(ARGV[0] == nil) then
31
+ c.usage
32
+ exit
33
+ end
34
+
35
+ Scriptroute::daemon_running_or_exit
36
+
37
+ if($Output != "") then
38
+ $stdout.reopen(File.open($Output,"a"))
39
+ end
40
+
41
+ Destination = (ARGV[0] =~ /(\d{1,3}\.){3}\d{1,3}/) ? ARGV[0] : Scriptroute.dns_lookup(ARGV[0])
42
+ puts Scriptroute::Rockettrace.new(Destination, $StartTTL, $UseTCP, $Repetitions).to_s(lambda { |x|
43
+ if($Numeric) then
44
+ x
45
+ elsif(x=='' || x==nil)
46
+ "[empty]"
47
+ else
48
+ Scriptroute.nameify(x)
49
+ end
50
+ })
51
+
data/bin/sr-traceroute ADDED
@@ -0,0 +1,35 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ require 'scriptroute'
4
+
5
+ Scriptroute::daemon_running_or_exit
6
+
7
+ probe = Scriptroute::UDP.new(12)
8
+
9
+ probe.ip_dst = Scriptroute::dns_lookup(ARGV[0])
10
+
11
+ unreach = false
12
+
13
+ puts "Traceroute to #{ARGV[0]} (#{probe.ip_dst})"
14
+
15
+ catch(:unreachable) do
16
+ ( 1..64 ).each { |ttl|
17
+ ( 1..3 ).each { |rep|
18
+ probe.ip_ttl = ttl
19
+ # some boxes refuse to reply to additional probes to the same uh_dport.
20
+ probe.uh_dport = 33434 + ttl + rep
21
+ packets = Scriptroute::send_train([ Struct::DelayedPacket.new(0,probe) ])
22
+ response = (packets[0].response) ? packets[0].response.packet : nil
23
+ if(response) then
24
+ puts '%d %s %5.3f ms' % [ ttl, response.ip_src, packets[0].rtt * 1000.0 ]
25
+ if(response.is_a?(Scriptroute::ICMP)) then
26
+ unreach = true if(response.icmp_type == Scriptroute::ICMP::ICMP_UNREACH)
27
+ end
28
+ else
29
+ puts '%d *' % [ ttl ]
30
+ end
31
+ $stdout.flush
32
+ }
33
+ throw :unreachable if(unreach)
34
+ }
35
+ end
data/bin/tulip ADDED
@@ -0,0 +1,183 @@
1
+ #! /usr/bin/env ruby
2
+
3
+ # require "srclient";
4
+ require "scriptroute";
5
+ require "scriptroute/tulip/helper.rb";
6
+ require "scriptroute/tulip/reordering.rb";
7
+ require "scriptroute/tulip/loss.rb";
8
+ require "scriptroute/tulip/queuing.rb";
9
+
10
+ FIXCLOCK = "/usr/bin/awk -f scriptroute/fixclock";
11
+
12
+ ################### defaults ################
13
+
14
+ $count = 1000;
15
+ $lag = 1000;
16
+ $spread = 0;
17
+ $start = 1;
18
+ $end = 30;
19
+
20
+ $skipRTrtrs = true;
21
+ $printFrequency = -1;
22
+ $allhops = true;
23
+ $dstonly = false;
24
+ $nonames = false;
25
+ $prefixpath = 0;
26
+
27
+ $verbose = 0;
28
+ $version = "0.0.1"
29
+
30
+ MAX_TRAIN = 4000;
31
+
32
+ #################### usage ##################
33
+ def usage()
34
+ puts "usage: tulip <reordering|loss|queuing> [options] <destination>\n";
35
+ puts "options:";
36
+ puts "--count <num>: number of measurements to use [#{$count}]";
37
+ puts "--lag <lag>: milliseconds to wait between successive measurements of the path [#{$lag}]";
38
+ puts "--spread <spread>: millisecond separation between probes in a single measurement [#{$spread}]";
39
+ puts "--start <start>: hop number to start diagnosis from [#{$start}]";
40
+ puts "--end <end>: hop number to end diagnosis at [#{$end}]";
41
+ puts "";
42
+ puts "--noskip: stop querying rate-limiting routers [skipping]";
43
+ puts "--mode <parallel|binary>: binary search not yet implemented";
44
+ puts "--printfrequency <frequency>: number of measurements to print the analysis [at the end]";
45
+ puts "--noallhops: use round trip measurements for hops that don't support forward primitives [on]";
46
+ puts "--dstonly: only probe end to end path [off]";
47
+ puts "--nonames: don't resolve ip addresses [resolve]";
48
+ puts "--prefixpath <hops>: number of initial hops to excuse for local load balancing [#{$prefixpath}]";
49
+ puts "";
50
+ puts "--help: display this message";
51
+ puts "--verbose <level>: level of verbosity (0-10) [#{$verbose}]";
52
+ puts "--version: print version information and exit";
53
+ puts "";
54
+ exit 1;
55
+ end
56
+
57
+ def printVersionAndExit()
58
+ puts "tulip version: #{$version}";
59
+ exit 0;
60
+ end
61
+
62
+ #################### command line processing #############
63
+
64
+ printVersionAndExit() if (ARGV.index("--version"));
65
+ usage() if (ARGV.length < 2);
66
+
67
+ pathology = ARGV.shift();
68
+ if (pathology[0,1] == "r") then
69
+ pathology = "reordering";
70
+ elsif (pathology[0,1] == "l") then
71
+ pathology = "loss";
72
+ elsif (pathology[0,1] == "q") then
73
+ pathology = "queuing";
74
+ else
75
+ puts "ERROR: unknown pathology";
76
+ usage();
77
+ end
78
+
79
+ switch = ARGV.shift();
80
+ while (switch and switch[0,2] == "--")
81
+ if (switch == "--count") then $count = ARGV.shift.to_i;
82
+ elsif (switch == "--lag") then $lag = ARGV.shift.to_i;
83
+ elsif (switch == "--spread") then $spread = ARGV.shift.to_f;
84
+ elsif (switch == "--start") then $start = ARGV.shift.to_i;
85
+ elsif (switch == "--end") then $end = ARGV.shift.to_i;
86
+ elsif (switch == "--printfrequency") then $printFrequency = ARGV.shift.to_i;
87
+ elsif (switch == "--help") then usage();
88
+ elsif (switch == "--verbose") then $verbose = ARGV.shift.to_i;
89
+ elsif (switch == "--noskip") then $skipRTrtrs = false;
90
+ elsif (switch == "--noallhops") then $allhops = false;
91
+ elsif (switch == "--dstonly") then $dstonly = true;
92
+ elsif (switch == "--nonames") then $nonames = true;
93
+ elsif (switch == "--prefixpath") then $prefixpath = ARGV.shift.to_i;
94
+ else
95
+ puts "ERROR: unknown option\n";
96
+ usage();
97
+ end
98
+ switch = ARGV.shift();
99
+ end
100
+
101
+ Scriptroute::daemon_running_or_exit
102
+
103
+ begin
104
+ destination = IPSocket.getaddress(switch) or switch;
105
+ rescue SocketError
106
+ puts "ERROR: unknown destination '#{switch}'";
107
+ usage();
108
+ end
109
+
110
+ if ($verbose>0) then
111
+ puts "pathology=%s count=%d lag=%d spread=%d start=%d end=%d verbose=%d destination=%s allhops=%s" % [pathology, $count, $lag, $spread, $start, $end, $verbose, destination, $allhops];
112
+ end
113
+
114
+ ########## determine hop characteristics #########
115
+
116
+ puts "tracing to #{destination} ......" if ($verbose >= 1);
117
+ tpath = Scriptroute::Tulip::TracePath.new(destination, !$nonames);
118
+
119
+ #todo: get rid of this ugly hack
120
+ $global_tpath = tpath;
121
+
122
+ puts " ----- pathto #{destination} ----- \n#{tpath.to_s}\n";
123
+ if (tpath.status_code == "incomplete") then
124
+ puts "incomplete trace\n";
125
+ end
126
+
127
+ puts "discovering routers that support forward path diagnosis .....\n" if ($verbose >=1);
128
+ hopDetails = Array.new();
129
+ if ($dstonly) then
130
+ hopDetails[tpath.path.length-1] = [destination, 255, "udp", true, destination];
131
+ else
132
+ middle = $start;
133
+ while (middle <= [$end, tpath.path.length - 1].min)
134
+
135
+ router, ttl = tpath.path[middle].ip, tpath.path[middle].hop;
136
+
137
+ ## for loss and reordering (ip-ids) ##
138
+ if (pathology == "reordering" || pathology == "loss") then
139
+ if (Scriptroute::Tulip::LangChecker.increasingIPIDs(destination, ttl, "udp")) then
140
+ hopDetails[middle] = [destination, ttl, "udp", true, router];
141
+ else
142
+ subpath = Scriptroute::Tulip::TracePath.new(router);
143
+ subset = tpath.subset(subpath);
144
+ puts " ----- subpathto #{router} (#{middle}) is #{subset} -----\n#{subpath.to_s}\n" if ($verbose>0);
145
+ if (subset) then
146
+ type, canCheckForward = Scriptroute::Tulip::LangChecker.getBestOption4IPIDs(router, "echo", "udp", "tcp", "tstamp");
147
+ if (canCheckForward) then
148
+ hopDetails[middle] = [router, 255, type, true, router]
149
+ else
150
+ hopDetails[middle] = [destination, ttl, "udp", false, router] if ($allhops or middle == tpath.path.length - 1);
151
+ end
152
+ else
153
+ hopDetails[middle] = [destination, ttl, "udp", false, router] if ($allhops or middle == tpath.path.length - 1);
154
+ end
155
+ end
156
+ ## queuing (timestamps)
157
+ else
158
+ if Scriptroute::Tulip::(LangChecker.getBestOption(router, "tstamp")) then
159
+ subpath = Scriptroute::Tulip::TracePath.new(router);
160
+ subset = tpath.subset(subpath);
161
+ puts " ----- subpathto #{router} (#{middle}) is #{subset} -----\n#{subpath.to_s}\n" if ($verbose>0);
162
+ if (subset) then
163
+ hopDetails[middle] = [router, 255, "tstamp", true, router];
164
+ else
165
+ hopDetails[middle] = [router, 255, "tstamp", false, router] if ($allhops or middle == tpath.path.length - 1);
166
+ end
167
+ else
168
+ hopDetails[middle] = [destination, ttl, "udp", false, router] if ($allhops or middle == tpath.path.length - 1);
169
+ end
170
+ end
171
+
172
+ middle+=1;
173
+ end
174
+ end
175
+
176
+
177
+ (1..hopDetails.length-1).map { |i| puts "hopdetails: #{tpath.path[i].hop}. #{hopDetails[i].join(" ")}" if (hopDetails[i])} if ($verbose>0);
178
+
179
+
180
+ if (pathology == "reordering") then Scriptroute::Tulip::ReorderingDoctor.new(hopDetails);
181
+ elsif (pathology == "loss") then Scriptroute::Tulip::LossDoctor.new(hopDetails);
182
+ else Scriptroute::Tulip::QueuingDoctor.new(hopDetails);
183
+ end
@@ -0,0 +1,327 @@
1
+ # @author Neil Spring
2
+
3
+ require 'socket'
4
+ require 'timeout'
5
+ require 'base64'
6
+ require 'resolv'
7
+ require 'scriptroute/packets'
8
+ require 'scriptroute/ally'
9
+ require 'scriptroute/rockettrace'
10
+ require 'scriptroute/nameify'
11
+
12
+ module Scriptroute
13
+
14
+ class ScriptrouteError < StandardError
15
+ end
16
+
17
+ # A ScriptrouteConnection is an object that wraps the TCP
18
+ # socket used to connect to a scriptroute daemon. It likely
19
+ # need not be used directly, unless accessing low level
20
+ # scriptroute commands not wrapped by the general
21
+ # Scriptroute module
22
+ class ScriptrouteConnection
23
+ Client_name = "%s(%d)" % [ defined?(Etc) ? Etc.getlogin : ENV['USER'], Process.uid ]
24
+ # this version is designed to emulate the 0.4.14 version of srinterpreter.
25
+ VERSION = '0.4.14'
26
+ def initialize
27
+ begin
28
+ timeout(5) do
29
+ @s = TCPSocket.new 'localhost', 3356
30
+ end
31
+ reply = ""
32
+ reply = one_line_command( "interpret v%s %s\n" % [ VERSION, Client_name ] )
33
+ if reply =~ /proceed( Hz=(\d+))/ then
34
+ # puts "negotiated."
35
+ else
36
+ puts "failed to negotiate: %s" % reply
37
+ end
38
+ rescue Errno::ECONNREFUSED => e
39
+ $stderr.puts "Connection refused connecting to scriptrouted, ensure that it is running"
40
+ raise e
41
+ end
42
+ end
43
+ # @param t [String] the command to issue, newline optional
44
+ # @return [String, nil] the one-line reply, or nil if the connection timed out or was terminated.
45
+ def one_line_command(t)
46
+ begin
47
+ reply = nil
48
+ timeout(2) do
49
+ issue_command t
50
+ reply = @s.readline
51
+ end
52
+ rescue EOFError
53
+ end
54
+ return reply
55
+ end
56
+ # @return [Hash] the configuration of the scriptroute daemon
57
+ def get_config
58
+ ret = Hash.new
59
+ timeout(5) do
60
+ issue_command "showconfig\n"
61
+ l = "do/while"
62
+ # showconfig ends reply with an empty line.
63
+ while l !~ /^#done/ && l !~ /^$/
64
+ l = @s.readline
65
+ if l =~ /^(\S+)\s+=\s+(.+)$/ then
66
+ ret[$1] = $2
67
+ elsif l =~ /^(\S+)\s+=\s*$/ then
68
+ ret[$1] = nil
69
+ elsif l =~ /^$/ then
70
+ # end.
71
+ else
72
+ puts "unparsed config: %s" % l
73
+ end
74
+ end
75
+ end
76
+ ret
77
+ end
78
+ # @param t [String] the command to issue, newline optional
79
+ def issue_command(t)
80
+ # $stderr.puts "writing %s" % t
81
+ if t[-1] == "\n" then
82
+ @s.write t
83
+ else
84
+ @s.write "%s\n" % [ t ]
85
+ end
86
+ end
87
+ # @return [String,nil] A one-line reply, or nil if the connection terminated.
88
+ def get_reply
89
+ begin
90
+ @s.readline
91
+ rescue EOFError
92
+ nil
93
+ end
94
+ end
95
+ end
96
+
97
+ # A DelayedPacket is for constructing trains in send_train.
98
+ Struct.new("DelayedPacket", :delay, :packet)
99
+
100
+ # TimedPacket is a time, packet tuple, with a tsc value thrown in in case its useful
101
+ class TimedPacket
102
+ # @return [Float,nil]
103
+ attr_accessor :time
104
+ # @return [Fixnum,nil] The output of rdtsc can be a more
105
+ # useful value in calculating rtt when NTP's adjustments
106
+ # via skew cause trouble.
107
+ attr_accessor :tsc
108
+ # @return [IPv4]
109
+ attr_accessor :packet
110
+
111
+ # @param time [Float,nil] Seconds since the epoch, or nil if we didn't see the packet leave due to pcap (happens)
112
+ # @param tsc [Fixnum,nil] Value of the cycle counter (rdtsc) or nil if not supported
113
+ # @param packet [IPv4] The packet received.
114
+ def initialize(time, tsc, packet)
115
+ raise ArgumentError, "no packet" unless packet
116
+ raise ArgumentError, "packet of the wrong class" unless packet.is_a?(IPv4)
117
+ @time = time
118
+ @tsc = tsc
119
+ @packet = packet
120
+ end
121
+ end
122
+
123
+ # A ProbeResponse is a pair of a probe and its response.
124
+ # Scriptroute is designed around the idea that a general
125
+ # purpose engine can recognize the response to any probe,
126
+ # and be in charge of doing so, so that measurement tools
127
+ # need not have the rights to look at every packet.
128
+ #
129
+ # This design does limit somewhat, since probes that are
130
+ # capable of soliciting more than one response (e.g., via
131
+ # fragmentation) will not be managed properly.
132
+ class ProbeResponse
133
+ # @return [TimedPacket]
134
+ attr_accessor :probe
135
+ # @return [TimedPacket]
136
+ attr_accessor :response
137
+ # @return [Float,nil] Provides the apparent round trip time of this probe-response pair, or nil if either time is missing.
138
+ def rtt
139
+ if response and probe and probe.time then
140
+ response.time - probe.time
141
+ else
142
+ nil
143
+ end
144
+ end
145
+ end
146
+ private
147
+
148
+ # Connection pool in case the script requires more than one connection to the server (for concurrent tests).
149
+ class ConnectionPool
150
+ @@connections_cache = []
151
+ # Connection pool mutex.
152
+ @@connections_mutex = Mutex.new
153
+ # Fetch from the connection pool or create a new connection
154
+ # @return [ScriptrouteConnection]
155
+ def ConnectionPool.get_idle_connection
156
+ @@connections_mutex.lock
157
+ if @@connections_cache.empty? then
158
+ @@connections_mutex.unlock
159
+ return ScriptrouteConnection.new
160
+ else
161
+ ret = @@connections_cache.shift
162
+ @@connections_mutex.unlock
163
+ return ret
164
+ end
165
+ end
166
+ # @param c [ScriptrouteConnection] the connection to return to the pool
167
+ # @return [void]
168
+ def ConnectionPool.return_idle_connection(c)
169
+ @@connections_mutex.synchronize {
170
+ @@connections_cache.push(c)
171
+ }
172
+ end
173
+ end
174
+ public
175
+ # Take a block to be executed with a ScriptrouteConnection
176
+ # from the pool. This is the function to use, since it
177
+ # manages the pooled connections explicitly. A leak in
178
+ # connections would be bad.
179
+ # @yield [ScriptrouteConnection] the connection for this block.
180
+ # @return the output of the block
181
+ def Scriptroute::with_scriptroute_connection
182
+ c = ConnectionPool.get_idle_connection
183
+ r = yield c
184
+ ConnectionPool.return_idle_connection(c)
185
+ r
186
+ end
187
+ # Check if the daemon is running by making a connection or
188
+ # checking the pool for an unused but working connection.
189
+ # @return [Boolean]
190
+ def Scriptroute::is_daemon_running?
191
+ begin
192
+ with_scriptroute_connection do |c|
193
+ end
194
+ return true
195
+ rescue Errno::ECONNREFUSED
196
+ return false
197
+ end
198
+ end
199
+ # Exit failure if the scriptroute daemon does not appear
200
+ # to be running. This is useful at the beginning of
201
+ # scripts that expect the daemon to run, to avoid adding
202
+ # extra error checking later.
203
+ # @return [true] if the script does ot exit because the daemon
204
+ # is not running.
205
+ def Scriptroute::daemon_running_or_exit
206
+ begin
207
+ with_scriptroute_connection do |c|
208
+ end
209
+ return true
210
+ rescue Errno::ECONNREFUSED
211
+ puts "Ensure that the scriptroute daemon is running and try again"
212
+ exit 1
213
+ end
214
+ end
215
+ # Query for the version of the daemon; useful if there's a
216
+ # feature only supported in a particular version. @return
217
+ # @return [String] the version string provided by of the running daemon
218
+ def Scriptroute::DaemonVersion
219
+ with_scriptroute_connection do |c|
220
+ puts c.one_line_command("version\n")
221
+ end
222
+ end
223
+ # @return [String] An IP address associated with the
224
+ # hostname. Currently just invokes Resolv.getaddress.
225
+ def Scriptroute::dns_lookup(name)
226
+ Resolv.getaddress name
227
+ end
228
+ # @return [Hash] the configuration of the running daemon,
229
+ # useful for checking rate limiting parameters or filters
230
+ # if a specially configured daemon is needed.
231
+ def Scriptroute::DaemonConfig
232
+ ret = nil
233
+ with_scriptroute_connection do |c|
234
+ ret = c.get_config
235
+ end
236
+ ret
237
+ end
238
+ # no op for backward compatibility with the srinterpreter version
239
+ # that had a dedicated packet instance
240
+ # @param s [String] A marshaled packet.
241
+ # @return [String] The input parameter, which is sufficient for this implementation of {Scriptroute::send_train}.
242
+ def Scriptroute::pkt_from_string(s)
243
+ s
244
+ end
245
+ # This is the nut.
246
+ # @param train [Array<Struct::DelayedPacket,Array>] an array of Struct::DelayedPacket entries or arrays containing delay, packet pairs.
247
+ # @return [Array<Scriptroute::ProbeResponse>] an array of Scriptroute::ProbeResponse entries, comprising a probe and response.
248
+ def Scriptroute::send_train(train)
249
+ ret = nil
250
+ return [] if train.empty? # easy?
251
+ with_scriptroute_connection do |c|
252
+ # issue the send train command.
253
+ i = 1;
254
+ total_delay = 0
255
+ train.map! { |boxcar|
256
+ raise ArgumentError, 'nil entry' unless boxcar
257
+ if boxcar.is_a?(Array) then
258
+ Struct::DelayedPacket.new(*boxcar)
259
+ else
260
+ raise ArgumentError, 'not a boxcar or an array' unless boxcar.is_a?(Struct::DelayedPacket)
261
+ boxcar
262
+ end
263
+ }
264
+ train.each { |boxcar|
265
+ # needs validation.
266
+ delay = boxcar[:delay]
267
+ packet = boxcar[:packet]
268
+ raise "no packet" unless packet
269
+ if packet.is_a?(Scriptroute::IPv4) then
270
+ packet = packet.marshal
271
+ end
272
+ raise "packet is #{packet.class}, not a string" unless packet.is_a?(String)
273
+ encoded_packet = Base64.strict_encode64(packet) # strict_encode means no line feeds added.
274
+ c.issue_command "sendtrain %d/%d %f %d %s\n" % [ i, train.length, delay<0 ? 0 : delay, encoded_packet.length, encoded_packet ]
275
+ i+=1
276
+ total_delay += delay
277
+ }
278
+
279
+ # allocate space for the responses, array of probe response pairs, each of which will be a time/packet pair.
280
+ ret = Array.new(i-1) { ProbeResponse.new }
281
+
282
+ # collect, waiting maybe 5 minutes more than needed just in case the daemon hangs on us.
283
+ begin
284
+ timeout(total_delay + 300) do
285
+ while l = c.get_reply and l !~ /^done/ and l =~ /\S+/ do
286
+ if l =~ /^ERROR/ then
287
+ # have to throw an exception, although individual packet errors are possible, that's
288
+ # not communicated by the daemon.
289
+ $stderr.puts l
290
+ if l=~ /disjoint train \missing packet #(\d+)/ then
291
+ ret[ $1.to_i ].probe = nil
292
+ ret[ $1.to_i ].response = nil
293
+ end
294
+ raise ScriptrouteError, l
295
+ else
296
+ if l =~ /^(-?\d+\.\d+)\/(\d+) (\d+)([<>]) \d+ (\S+)$/ then
297
+ tv_s = $1.to_f
298
+ rdtsc = $2
299
+ pk = $3.to_i - 1
300
+ io = ($4 == '>') ? 0 : 1
301
+ st = $5
302
+ packet_string = Base64.strict_decode64(st)
303
+ p = IPv4.creator(packet_string)
304
+ tv_s = nil if tv_s < 0 # didn't see it leave.
305
+ tp = TimedPacket.new(tv_s, rdtsc, p)
306
+ if io == 0 then
307
+ ret[ pk ].probe = tp
308
+ else
309
+ ret[ pk ].response = tp
310
+ end
311
+ else
312
+ puts "unparsed send_train response: #{l}"
313
+ end
314
+ end
315
+ end # while
316
+ end # timeout
317
+ rescue TimeoutError
318
+ $stderr.puts "timed out parsing responses for send_train"
319
+ end
320
+ end
321
+ return ret
322
+ end
323
+ end
324
+
325
+ # Local Variables:
326
+ # compile-command: "rake test"
327
+ # End: