lib/sippy_cup/scenario.rb in sippy_cup-0.1.0 vs lib/sippy_cup/scenario.rb in sippy_cup-0.1.1
- old
+ new
@@ -1,6 +1,7 @@
require 'nokogiri'
+require 'yaml'
module SippyCup
class Scenario
VALID_DTMF = %w{0 1 2 3 4 5 6 7 8 9 0 * # A B C D}.freeze
MSEC = 1_000
@@ -9,17 +10,18 @@
builder = Nokogiri::XML::Builder.new do |xml|
xml.scenario name: name
end
parse_args args
-
- @filename = name.downcase.gsub(/\W+/, '_')
+ @filename = args[:filename] || name.downcase.gsub(/\W+/, '_')
+ @filename = File.expand_path @filename
@doc = builder.doc
@media = Media.new @from_addr, @from_port, @to_addr, @to_port
+ @scenario_opts = get_scenario_opts args
@scenario = @doc.xpath('//scenario').first
- instance_eval &block
+ instance_eval &block if block_given?
end
def parse_args(args)
raise ArgumentError, "Must include source IP:PORT" unless args.keys.include? :source
raise ArgumentError, "Must include destination IP:PORT" unless args.keys.include? :destination
@@ -27,10 +29,19 @@
@from_addr, @from_port = args[:source].split ':'
@to_addr, @to_port = args[:destination].split ':'
@from_user = args[:from_user] || "sipp"
end
+ def get_scenario_opts(args)
+ defaults = { source: "#{@from_addr}", destination: "#{@to_addr}",
+ scenario: "#{@filename}.xml", max_concurrent: 10,
+ calls_per_second: 5, number_of_calls: 20 }
+
+ opts = args.select {|k,v| true unless [:source, :destination, :filename].include? k}
+ defaults.merge! args
+ end
+
def compile_media
@media.compile!
end
def sleep(seconds)
@@ -53,11 +64,11 @@
CSeq: [cseq] INVITE
Contact: sip:#{@from_user}@[local_ip]:[local_port]
Max-Forwards: 100
Content-Type: application/sdp
Content-Length: [len]
-
+
v=0
o=user1 53655765 2353687637 IN IP[local_ip_type] [local_ip]
s=-
c=IN IP[media_ip_type] [media_ip]
t=0 0
@@ -74,18 +85,18 @@
opts[:optional] = true if opts[:optional].nil?
opts.merge! response: 100
@scenario << new_recv(opts)
end
alias :receive_100 :receive_trying
-
+
def receive_ringing(opts = {})
opts[:optional] = true if opts[:optional].nil?
opts.merge! response: 180
@scenario << new_recv(opts)
end
alias :receive_180 :receive_ringing
-
+
def receive_progress(opts = {})
opts[:optional] = true if opts[:optional].nil?
opts.merge! response: 183
@scenario << new_recv(opts)
end
@@ -98,10 +109,20 @@
recv['rrs'] = true
@scenario << recv
end
alias :receive_200 :receive_answer
+ ##
+ # Shortcut method that tells SIPp optionally receive
+ # SIP 100, 180, and 183 messages, and require a SIP 200 message.
+ def wait_for_answer(opts = {})
+ receive_trying({optional: true}.merge opts)
+ receive_ringing({optional: true}.merge opts)
+ receive_progress({optional: true}.merge opts)
+ receive_answer opts
+ end
+
def ack_answer(opts = {})
msg = <<-ACK
ACK [next_url] SIP/2.0
Via: SIP/2.0/[transport] [local_ip]:[local_port];branch=[branch]
@@ -135,11 +156,11 @@
delay = 0.250 * MSEC # FIXME: Need to pass this down to the media layer
digits.split('').each do |digit|
raise ArgumentError, "Invalid DTMF digit requested: #{digit}" unless VALID_DTMF.include? digit
@media << "dtmf:#{digit}"
- @media << "silence:#{delay}"
+ @media << "silence:#{delay.to_i}"
pause delay * 2
end
end
def send_bye(opts = {})
@@ -183,11 +204,15 @@
def to_xml
@doc.to_xml
end
def compile!
- xml_file = File.open "#{@filename}.xml", 'w' do |file|
+ File.open "#{@filename}.xml", 'w' do |file|
file.write @doc.to_xml
+ end
+
+ File.open "#{@filename}.yml", 'w' do |file|
+ file.write @scenario_opts.to_yaml
end
compile_media.to_file filename: "#{@filename}.pcap"
end
private