quaff 0.1.0 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.
@@ -0,0 +1,24 @@
1
+ module Quaff
2
+ module Auth
3
+ def Auth.gen_nonce auth_pairs, username, passwd, method, sip_uri
4
+ a1 = username + ":" + auth_pairs["realm"] + ":" + passwd
5
+ a2 = method + ":" + sip_uri
6
+ ha1 = Digest::MD5::hexdigest(a1)
7
+ ha2 = Digest::MD5::hexdigest(a2)
8
+ digest = Digest::MD5.hexdigest(ha1 + ":" + auth_pairs["nonce"] + ":" + ha2)
9
+ return digest
10
+ end
11
+
12
+ def Auth.gen_auth_header auth_line, username, passwd, method, sip_uri
13
+ # Split auth line on commas
14
+ auth_pairs = {}
15
+ auth_line.sub("Digest ", "").split(",") .each do |pair|
16
+ key, value = pair.split "="
17
+ auth_pairs[key.gsub(" ", "")] = value.gsub("\"", "").gsub(" ", "")
18
+ end
19
+ digest = gen_nonce auth_pairs, username, passwd, method, sip_uri
20
+ return %Q!Digest username="#{username}",realm="#{auth_pairs['realm']}",nonce="#{auth_pairs['nonce']}",uri="#{sip_uri}",response="#{digest}",algorithm="#{auth_pairs['algorithm']}",opaque="#{auth_pairs['opaque']}"!
21
+ # Return Authorization header with fields username, realm, nonce, uri, nc, cnonce, response, opaque
22
+ end
23
+ end
24
+ end
@@ -1,22 +1,25 @@
1
1
  # -*- coding: us-ascii -*-
2
2
  require_relative './utils.rb'
3
3
  require_relative './sources.rb'
4
+ require_relative './auth.rb'
5
+ require_relative './message.rb'
4
6
 
5
- class CSeq
7
+ module Quaff
8
+ class CSeq # :nodoc:
6
9
  def initialize cseq_str
7
10
  @num, @method = cseq_str.split
8
11
  @num = @num.to_i
9
12
  end
10
13
 
11
14
  def increment
12
- @num = @num +1
15
+ @num = @num + 1
13
16
  to_s
14
17
  end
15
18
 
16
19
  def to_s
17
20
  "#{@num.to_s} #{@method}"
18
21
  end
19
-
22
+
20
23
  end
21
24
 
22
25
  class Call
@@ -24,7 +27,7 @@ class Call
24
27
 
25
28
  def initialize(cxn,
26
29
  cid,
27
- uri="sip:5557777888@#{QuaffUtils.local_ip}",
30
+ uri="sip:5557777888@#{Utils::local_ip}",
28
31
  destination=nil,
29
32
  target_uri=nil)
30
33
  @cxn = cxn
@@ -45,9 +48,9 @@ class Call
45
48
  end
46
49
 
47
50
  def update_branch
48
- @last_Via = "SIP/2.0/#{@cxn.transport} #{QuaffUtils.local_ip}:#{@cxn.local_port};rport;branch=#{QuaffUtils.new_branch}"
51
+ @last_Via = "SIP/2.0/#{@cxn.transport} #{Quaff::Utils.local_ip}:#{@cxn.local_port};rport;branch=#{Quaff::Utils::new_branch}"
49
52
  end
50
-
53
+
51
54
  def create_dialog msg
52
55
  set_callee msg.first_header("Contact")
53
56
  @routeset = msg.all_headers("Record-Route")
@@ -56,23 +59,11 @@ class Call
56
59
  end
57
60
  end
58
61
 
59
- def recv_something
60
- data = @cxn.get_new_message @cid
61
- @retrans = nil
62
- @src = data['source']
63
- @last_To = data["message"].header("To")
64
- @last_From = data["message"].header("From")
65
- @sip_destination ||= data["message"].header("From")
66
- @last_Via = data["message"].headers["Via"]
67
- @last_CSeq = CSeq.new(data["message"].header("CSeq"))
68
- data
69
- end
70
-
71
62
  def set_callee uri
72
63
  if /<(.*)>/ =~ uri
73
64
  uri = $1
74
65
  end
75
-
66
+
76
67
  @sip_destination = "#{uri}"
77
68
  @last_To = "<#{uri}>"
78
69
  end
@@ -90,8 +81,9 @@ class Call
90
81
  rescue
91
82
  raise "#{ @uri } timed out waiting for #{ method }"
92
83
  end
93
- unless data["message"].type == :request and Regexp.new(method) =~ data["message"].method
94
- raise (data['message'].to_s || "Message is nil!")
84
+ unless data["message"].type == :request \
85
+ and Regexp.new(method) =~ data["message"].method
86
+ raise((data['message'].to_s || "Message is nil!"))
95
87
  end
96
88
  data
97
89
  end
@@ -102,44 +94,94 @@ class Call
102
94
  rescue
103
95
  raise "#{ @uri } timed out waiting for #{ code }"
104
96
  end
105
- unless data["message"].type == :response and Regexp.new(code) =~ data["message"].status_code
97
+ unless data["message"].type == :response \
98
+ and Regexp.new(code) =~ data["message"].status_code
106
99
  raise "Expected #{ code}, got #{data["message"].status_code || data['message']}"
107
100
  end
108
101
  data
109
102
  end
110
103
 
111
- def send_response(code, retrans=nil, headers={})
112
- msg = build_message headers, :response, code
104
+ def send_response(code, phrase, body="", retrans=nil, headers={})
105
+ method = nil
106
+ msg = build_message headers, body, :response, method, code, phrase
113
107
  send_something(msg, retrans)
114
108
  end
115
109
 
116
- def send_request(method, sdp=true, retrans=nil, headers={})
117
- sdp="v=0
118
- o=user1 53655765 2353687637 IN IP4 #{QuaffUtils.local_ip}
119
- s=-
120
- c=IN IP4 #{QuaffUtils.local_ip}
121
- t=0 0
122
- m=audio 7000 RTP/AVP 0
123
- a=rtpmap:0 PCMU/8000"
110
+ def send_request(method, body="", headers={})
111
+ msg = build_message headers, body, :request, method
112
+ send_something(msg, nil)
113
+ end
124
114
 
125
- msg = build_message headers, :request, method
126
- send_something(msg, retrans)
115
+ def end_call
116
+ @cxn.mark_call_dead @cid
117
+ end
118
+
119
+
120
+ def clear_tag str
121
+ str
122
+ end
123
+
124
+ def clone_details other_message
125
+ @headers['To'] = [clear_tag(other_message.header("To"))]
126
+ @headers['From'] = [clear_tag(other_message.header("From"))]
127
+ @headers['Route'] = [other_message.header("Route")]
128
+ end
129
+
130
+ def get_next_hop header
131
+ /<sip:(.+@)?(.+):(\d+);(.*)>/ =~ header
132
+ sock = TCPSocket.new $2, $3
133
+ return TCPSource.new sock
134
+ end
135
+
136
+ def register username=@username, password=@password, expires="3600"
137
+ @username, @password = username, password
138
+ set_callee(@uri)
139
+ send_request("REGISTER", "", { "Expires" => expires.to_s })
140
+ response_data = recv_response("401|200")
141
+ if response_data['message'].status_code == "401"
142
+ send_request("ACK")
143
+ auth_hdr = Quaff::Auth.gen_auth_header response_data['message'].header("WWW-Authenticate"), username, password, "REGISTER", @uri
144
+ update_branch
145
+ send_request("REGISTER", "", {"Authorization" => auth_hdr, "Expires" => expires.to_s, "CSeq" => "2 REGISTER"})
146
+ recv_response("200")
147
+ end
148
+ return true
149
+ end
150
+
151
+ def unregister
152
+ register @username, @password, 0
153
+ end
154
+
155
+ private
156
+ def recv_something
157
+ data = @cxn.get_new_message @cid
158
+ @retrans = nil
159
+ @src = data['source']
160
+ @last_To = data["message"].header("To")
161
+ @last_From = data["message"].header("From")
162
+ @sip_destination ||= data["message"].header("From")
163
+ @last_Via = data["message"].headers["Via"]
164
+ @last_CSeq = CSeq.new(data["message"].header("CSeq"))
165
+ data
127
166
  end
128
167
 
129
- def build_message headers, type, method_or_code
168
+
169
+
170
+ def build_message headers, body, type, method=nil, code=nil, phrase=nil
130
171
  defaults = {
131
172
  "From" => @last_From,
132
173
  "To" => @last_To,
133
174
  "Call-ID" => @cid,
134
- "CSeq" => (/\d+/ =~ method_or_code) ? @last_CSeq.to_s : (method_or_code == "ACK") ? @last_CSeq.increment : "1 #{method_or_code}",
175
+ "CSeq" => (type == :response) ? @last_CSeq.to_s : (method == "ACK") ? @last_CSeq.increment : "1 #{method}",
135
176
  "Via" => @last_Via,
136
177
  "Max-Forwards" => "70",
137
178
  "Content-Length" => "0",
138
179
  "User-Agent" => "Quaff SIP Scripting Engine",
139
- "Contact" => "<sip:quaff@#{QuaffUtils.local_ip}:#{@cxn.local_port};transport=#{@cxn.transport};ob>",
180
+ "Contact" => "<sip:quaff@#{Utils::local_ip}:#{@cxn.local_port};transport=#{@cxn.transport};ob>",
140
181
  }
141
182
 
142
- if type == :request
183
+ is_request = method.nil?
184
+ if is_request
143
185
  defaults['Route'] = @routeset
144
186
  else
145
187
  defaults['Record-Route'] = @routeset
@@ -147,25 +189,8 @@ class Call
147
189
 
148
190
  defaults.merge! headers
149
191
 
192
+ SipMessage.new(method, code, phrase, @sip_destination, body, defaults.merge!(headers)).to_s
150
193
 
151
- if type == :request
152
- msg = "#{method_or_code} #{@sip_destination} SIP/2.0\r\n"
153
- else
154
- msg = "SIP/2.0 #{ method_or_code }\r\n"
155
- end
156
-
157
- defaults.each do |key, value|
158
- if value.nil?
159
- elsif not value.kind_of? Array
160
- msg += "#{key}: #{value}\r\n"
161
- else value.each do |subvalue|
162
- msg += "#{key}: #{subvalue}\r\n"
163
- end
164
- end
165
- end
166
- msg += "\r\n"
167
-
168
- msg
169
194
  end
170
195
 
171
196
  def send_something(msg, retrans)
@@ -188,43 +213,5 @@ class Call
188
213
  end
189
214
  end
190
215
 
191
- def end_call
192
- @cxn.mark_call_dead @cid
193
- end
194
-
195
- def clear_tag str
196
- str
197
- end
198
-
199
- def clone_details other_message
200
- @headers['To'] = [clear_tag(other_message.header("To"))]
201
- @headers['From'] = [clear_tag(other_message.header("From"))]
202
- @headers['Route'] = [other_message.header("Route")]
203
- end
204
-
205
- def get_next_hop header
206
- /<sip:(.+@)?(.+):(\d+);(.*)>/ =~ header
207
- sock = TCPSocket.new $2, $3
208
- return TCPSource.new sock
209
- end
210
-
211
- def register username=@username, password=@password, expires="3600"
212
- @username, @password = username, password
213
- set_callee(@uri)
214
- send_request("REGISTER", nil, nil, { "Expires" => expires.to_s })
215
- response_data = recv_response("401|200")
216
- if response_data['message'].status_code == "401"
217
- send_request("ACK")
218
- auth_hdr = gen_auth_header response_data['message'].header("WWW-Authenticate"), username, password, "REGISTER", @uri
219
- update_branch
220
- send_request("REGISTER", nil, nil, {"Authorization" => auth_hdr, "Expires" => expires.to_s})
221
- recv_response("200")
222
- end
223
- return true
224
- end
225
-
226
- def unregister
227
- register @username, @password, 0
228
- end
229
-
216
+ end
230
217
  end
@@ -5,6 +5,7 @@ require 'timeout'
5
5
  require_relative './sip_parser.rb'
6
6
  require_relative './sources.rb'
7
7
 
8
+ module Quaff
8
9
  class BaseEndpoint
9
10
  attr_accessor :msg_trace
10
11
 
@@ -31,6 +32,31 @@ class BaseEndpoint
31
32
  @lport
32
33
  end
33
34
 
35
+ def add_call_id cid
36
+ @messages[cid] ||= Queue.new
37
+ end
38
+
39
+ def get_new_call_id time_limit=5
40
+ Timeout::timeout(time_limit) { @call_ids.deq }
41
+ end
42
+
43
+ def get_new_message(cid, time_limit=5)
44
+ Timeout::timeout(time_limit) { @messages[cid].deq }
45
+ end
46
+
47
+ def mark_call_dead(cid)
48
+ @messages.delete cid
49
+ now = Time.now
50
+ @dead_calls[cid] = now + 30
51
+ @dead_calls = @dead_calls.keep_if {|k, v| v > now}
52
+ end
53
+
54
+ def send(data, source)
55
+ puts "Endpoint on #{@lport} sending #{data} to #{source.inspect}" if @msg_trace
56
+ source.send(@cxn, data)
57
+ end
58
+
59
+ private
34
60
  def initialize_queues
35
61
  @messages = {}
36
62
  @call_ids = Queue.new
@@ -59,30 +85,6 @@ class BaseEndpoint
59
85
  end
60
86
  end
61
87
 
62
- def add_call_id cid
63
- @messages[cid] ||= Queue.new
64
- end
65
-
66
- def get_new_call_id time_limit=5
67
- Timeout::timeout(time_limit) { @call_ids.deq }
68
- end
69
-
70
- def get_new_message(cid, time_limit=5)
71
- Timeout::timeout(time_limit) { @messages[cid].deq }
72
- end
73
-
74
- def mark_call_dead(cid)
75
- @messages.delete cid
76
- now = Time.now
77
- @dead_calls[cid] = now + 30
78
- @dead_calls = @dead_calls.keep_if {|k, v| v > now}
79
- end
80
-
81
- def send(data, source)
82
- puts "Endpoint on #{@lport} sending #{data} to #{source.inspect}" if @msg_trace
83
- source.send(@cxn, data)
84
- end
85
-
86
88
  end
87
89
 
88
90
  class TCPSIPEndpoint < BaseEndpoint
@@ -102,8 +104,22 @@ class TCPSIPEndpoint < BaseEndpoint
102
104
  return TCPSource.new ip, port
103
105
  end
104
106
 
105
- alias_method :new_connection, :new_source
107
+ def add_sock sock
108
+ @sockets.push sock
109
+ end
110
+
111
+ def terminate
112
+ oldsockets = @sockets.dup
113
+ @sockets = []
114
+ oldsockets.each do |s| s.close unless s.closed? end
115
+ mycxn = @cxn
116
+ @cxn = nil
117
+ mycxn.close
118
+ end
119
+
106
120
 
121
+ alias_method :new_connection, :new_source
122
+ private
107
123
  def recv_msg
108
124
  select_response = IO.select(@sockets, [], [], 0) || [[]]
109
125
  readable = select_response[0]
@@ -130,40 +146,21 @@ class TCPSIPEndpoint < BaseEndpoint
130
146
  queue_msg msg, TCPSourceFromSocket.new(sock)
131
147
  end
132
148
 
133
- def add_sock sock
134
- @sockets.push sock
135
- end
136
-
137
- def terminate
138
- oldsockets = @sockets.dup
139
- @sockets = []
140
- oldsockets.each do |s| s.close unless s.closed? end
141
- mycxn = @cxn
142
- @cxn = nil
143
- mycxn.close
144
- end
145
-
146
149
  end
147
150
 
148
151
  class UDPSIPEndpoint < BaseEndpoint
149
152
 
150
- def recv_msg
151
- data, addrinfo = @cxn.recvfrom(65535)
152
- @parser.parse_start
153
- msg = @parser.parse_partial(data)
154
- queue_msg msg, UDPSourceFromAddrinfo.new(addrinfo) unless msg.nil?
155
- end
156
-
157
153
  def transport
158
154
  "UDP"
159
155
  end
160
-
156
+
161
157
  def new_source ip, port
162
158
  return UDPSource.new ip, port
163
159
  end
164
-
160
+
165
161
  alias_method :new_connection, :new_source
166
-
162
+
163
+ private
167
164
  def initialize_connection(lport)
168
165
  @cxn = UDPSocket.new
169
166
  @cxn.bind('0.0.0.0', lport)
@@ -171,5 +168,14 @@ class UDPSIPEndpoint < BaseEndpoint
171
168
  @parser = SipParser.new
172
169
  end
173
170
 
171
+ def recv_msg
172
+ data, addrinfo = @cxn.recvfrom(65535)
173
+ @parser.parse_start
174
+ msg = @parser.parse_partial(data)
175
+ queue_msg msg, UDPSourceFromAddrinfo.new(addrinfo) unless msg.nil?
176
+ end
177
+
178
+
174
179
  end
175
180
 
181
+ end
@@ -0,0 +1,68 @@
1
+ module Quaff
2
+ class SipMessage
3
+ attr_accessor :method, :requri, :reason, :status_code, :headers
4
+ attr_reader :body
5
+
6
+ def initialize method=nil, status_code=nil, reason=nil,
7
+ req_uri=nil, body="", headers={}
8
+ @headers = headers
9
+ @method, @status_code, @reason, @req_uri = method, status_code, reason, req_uri
10
+ @body = body
11
+ @headers['Content-Length'] = [body.length]
12
+ end
13
+
14
+ def type
15
+ if @method
16
+ :request
17
+ elsif @status_code
18
+ :response
19
+ else
20
+ :nil
21
+ end
22
+ end
23
+
24
+ def all_headers hdr
25
+ return @headers[hdr]
26
+ end
27
+
28
+ def header hdr
29
+ return @headers[hdr][0] unless @headers[hdr].nil?
30
+ end
31
+
32
+ alias_method :first_header, :header
33
+
34
+ def body= body
35
+ @body = body
36
+ @headers['Content-Length'] = [body.length]
37
+ end
38
+
39
+ def to_s
40
+ msg = ""
41
+ if type == :request
42
+ msg << "#{@method} #{@req_uri} SIP/2.0\r\n"
43
+ else
44
+ msg << "SIP/2.0 #{@status_code} #{@reason}\r\n"
45
+ end
46
+
47
+ @headers.each do |key, value|
48
+ if value.nil?
49
+ elsif not value.kind_of? Array
50
+ msg << "#{key}: #{value}\r\n"
51
+ else value.each do |subvalue|
52
+ msg << "#{key}: #{subvalue}\r\n"
53
+ end
54
+ end
55
+ end
56
+ if body and body != ""
57
+ msg << "\r\n"
58
+ msg << body
59
+ else
60
+ msg << "\r\n"
61
+ end
62
+
63
+
64
+ msg
65
+ end
66
+
67
+ end
68
+ end
@@ -1,2 +1,3 @@
1
1
  require_relative './call.rb'
2
2
  require_relative './endpoint.rb'
3
+
@@ -1,133 +1,104 @@
1
1
  # -*- coding: us-ascii -*-
2
2
  require 'digest/md5'
3
+ require_relative './message.rb'
3
4
 
4
- class SipMessage
5
- attr_accessor :type, :method, :requri, :reason, :status_code, :headers, :body
6
-
7
- def initialize
8
- @headers = {}
9
- @method, @status_code, @reason, @req_uri = nil
10
- @body = ""
11
- end
12
-
13
- def all_headers hdr
14
- return @headers[hdr]
15
- end
16
-
17
- def header hdr
18
- return @headers[hdr][0] unless @headers[hdr].nil?
19
- end
20
-
21
- alias_method :first_header, :header
22
-
23
- def to_s
24
- "#{@method} #{@status_code} #{@headers}"
25
- end
26
-
27
- end
28
-
5
+ module Quaff
29
6
  class SipParser
30
7
  attr_reader :state
31
8
  def parse_start
32
- @buf = ""
33
- @msg = SipMessage.new
34
- @state = :blank
9
+ @buf = ""
10
+ @msg = SipMessage.new
11
+ @state = :blank
35
12
  end
36
13
 
37
14
  def parse_partial(data)
38
- return nil if data.nil?
39
- data.lines.each do |line|
40
- if @state == :blank
41
- parse_line_blank line
42
- elsif @state == :parsing_body
43
- parse_line_body line
44
- else
45
- parse_line_first_line_parsed line
46
- end
15
+ return nil if data.nil?
16
+ data.lines.each do |line|
17
+ line.rstrip!
18
+ if @state == :blank
19
+ parse_line_blank line
20
+ elsif @state == :parsing_body
21
+ parse_line_body line
22
+ else
23
+ parse_line_first_line_parsed line
47
24
  end
48
- if @state == :done
49
- return @msg
50
- else
51
- return nil
52
- end
25
+ end
26
+ if @state == :done
27
+ return @msg
28
+ else
29
+ return nil
30
+ end
53
31
  end
54
32
 
55
33
  def message_identifier(msg)
56
- msg.header("Call-ID")
34
+ msg.header("Call-ID")
57
35
  end
58
36
 
59
37
  def parse_line_blank line
60
- if line =~ %r!^([A-Z]+) (.+) SIP/2.0\r$!
61
- @msg.type = :request
62
- @msg.method = $1
63
- @msg.requri = $2
64
- @state = :first_line_parsed
65
- elsif line =~ %r!^SIP/2.0 (\d+) (.+)\r$!
66
- @msg.type = :response
67
- @msg.status_code = $1
68
- @msg.reason = $3 || ""
69
- @state = :first_line_parsed
70
- elsif line == "\r" or line == "\r\n"
71
- # skip empty lines
38
+ if line == ""
39
+ # skip empty lines
40
+ return
41
+ else
42
+ parts = line.split " ", 3
43
+ if parts[2] == "SIP/2.0"
44
+ # Looks like a SIP request
45
+ @msg.method = parts[0]
46
+ @msg.requri = parts[1]
47
+ @state = :first_line_parsed
48
+ return
49
+ elsif parts[0] == "SIP/2.0"
50
+ # Looks like a SIP response
51
+ @msg.status_code = parts[1]
52
+ @msg.reason = parts[2] || ""
53
+ @state = :first_line_parsed
54
+ return
72
55
  else
73
- raise line.inspect
56
+ raise parts.inspect
74
57
  end
58
+ end
59
+ # We haven't returned, so looks like a malformed line
60
+ raise line.inspect
75
61
  end
76
62
 
77
63
  def parse_line_first_line_parsed line
78
- if line =~ /^\s+(.+)\r/
79
- @msg.headers[@cur_hdr][-1] += " "
80
- @msg.headers[@cur_hdr][-1] += $1
81
- if $1 == "Content-Length"
82
- @state = :got_content_length
83
- else
84
- @state = :middle_of_headers
85
- end
86
- elsif line =~ /^([-\w]+)\s*:\s*(.+)\r/
87
- @msg.headers[$1] ||= []
88
- @msg.headers[$1].push $2
89
- @cur_hdr = $1
90
- if $1 == "Content-Length"
91
- @state = :got_content_length
92
- else
93
- @state = :middle_of_headers
94
- end
95
- elsif line == "\r" or line == "\r\n"
96
- if @state == :got_content_length and @msg.header("Content-Length").to_i > 0
97
- @state = :parsing_body
98
- else
99
- @state = :done
100
- end
101
- else raise line.inspect
64
+ if line.start_with? " "
65
+ @msg.headers[@cur_hdr][-1] += " "
66
+ @msg.headers[@cur_hdr][-1] += line.lstrip
67
+ if $1 == "Content-Length"
68
+ @state = :got_content_length
69
+ else
70
+ @state = :middle_of_headers
71
+ end
72
+ elsif line.include? ":"
73
+ parts = line.split ":", 2
74
+ header_name, header_value = parts[0].rstrip, parts[1].lstrip
75
+ @msg.headers[header_name] ||= []
76
+ @msg.headers[header_name].push header_value
77
+ @cur_hdr = header_name
78
+ if header_name == "Content-Length"
79
+ @state = :got_content_length
80
+ @msg.headers[header_name] = [header_value]
81
+ else
82
+ @state = :middle_of_headers
83
+ end
84
+ elsif line == ""
85
+ if @state == :got_content_length and @msg.header("Content-Length").to_i > 0
86
+ @state = :parsing_body
87
+ else
88
+ @state = :done
102
89
  end
90
+ else raise line.inspect
91
+ end
103
92
  end
104
93
 
105
94
  def parse_line_body line
106
- @msg.body << line
107
- if line == "\r" or @msg.body.length >= @msg.header("Content-Length").to_i
108
- @state = :done
109
- end
95
+ @msg.body << line
96
+ @msg.body << "\r\n"
97
+ if line == "" or @msg.body.length >= @msg.header("Content-Length").to_i
98
+ @state = :done
99
+ end
110
100
  end
111
101
 
112
- end
113
-
114
- def gen_nonce auth_pairs, username, passwd, method, sip_uri
115
- a1 = username + ":" + auth_pairs["realm"] + ":" + passwd
116
- a2 = method + ":" + sip_uri
117
- ha1 = Digest::MD5::hexdigest(a1)
118
- ha2 = Digest::MD5::hexdigest(a2)
119
- digest = Digest::MD5.hexdigest(ha1 + ":" + auth_pairs["nonce"] + ":" + ha2)
120
- return digest
121
102
  end
122
103
 
123
- def gen_auth_header auth_line, username, passwd, method, sip_uri
124
- # Split auth line on commas
125
- auth_pairs = {}
126
- auth_line.sub("Digest ", "").split(",") .each do |pair|
127
- key, value = pair.split "="
128
- auth_pairs[key.gsub(" ", "")] = value.gsub("\"", "").gsub(" ", "")
129
- end
130
- digest = gen_nonce auth_pairs, username, passwd, method, sip_uri
131
- return %Q!Digest username="#{username}",realm="#{auth_pairs['realm']}",nonce="#{auth_pairs['nonce']}",uri="#{sip_uri}",response="#{digest}",algorithm="#{auth_pairs['algorithm']}",opaque="#{auth_pairs['opaque']}"!
132
- # Return Authorization header with fields username, realm, nonce, uri, nc, cnonce, response, opaque
133
- end
104
+ end
@@ -1,5 +1,5 @@
1
1
  require 'socket'
2
-
2
+ module Quaff
3
3
  class Source
4
4
  def remote_ip
5
5
  @ip
@@ -38,12 +38,12 @@ class TCPSource < Source
38
38
  attr_reader :sock
39
39
 
40
40
  def initialize ip, port
41
- @sock = TCPSocket.new ip, port
41
+ @sock = TCPSocket.new ip, port
42
42
  @port, @ip = port, ip
43
43
  end
44
44
 
45
45
  def send _, data
46
- @sock.puts data
46
+ @sock.sendmsg data
47
47
  end
48
48
 
49
49
  def close cxn
@@ -58,3 +58,4 @@ class TCPSourceFromSocket < TCPSource
58
58
  @port, @ip = Socket.unpack_sockaddr_in(@sock.getpeername)
59
59
  end
60
60
  end
61
+ end
@@ -1,23 +1,23 @@
1
1
  require 'socket'
2
+ require 'facter'
2
3
 
3
- module QuaffUtils
4
- def QuaffUtils.local_ip
5
- Socket.ip_address_list.select {|i| !(i.ipv6? || i.ipv4_loopback?)}[0].ip_address
6
- end
4
+ module Quaff
7
5
 
8
- def local_ipv6
9
- Socket.ip_address_list.select {|i| !(i.ipv4? || i.ipv6_loopback?)}[0].ip_address
6
+ module Utils
7
+ def Utils.local_ip
8
+ Facter.value("ipaddress")
10
9
  end
11
10
 
12
- def pid
11
+ def Utils.pid
13
12
  Process.pid
14
13
  end
15
14
 
16
- def new_call_id
15
+ def Utils.new_call_id
17
16
  "#{pid}_#{Time.new.to_i}@#{local_ipv4}"
18
17
  end
19
18
 
20
- def QuaffUtils.new_branch
19
+ def Utils.new_branch
21
20
  "z9hG4bK#{Time.new.to_f}"
22
21
  end
23
22
  end
23
+ end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: quaff
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.0
4
+ version: 0.2.0
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,8 +9,24 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2013-08-24 00:00:00.000000000 Z
13
- dependencies: []
12
+ date: 2013-10-11 00:00:00.000000000 Z
13
+ dependencies:
14
+ - !ruby/object:Gem::Dependency
15
+ name: facter
16
+ requirement: !ruby/object:Gem::Requirement
17
+ none: false
18
+ requirements:
19
+ - - ! '>='
20
+ - !ruby/object:Gem::Version
21
+ version: 1.7.3
22
+ type: :runtime
23
+ prerelease: false
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.7.3
14
30
  description: A Ruby library for writing SIP test scenarios
15
31
  email: rkd@rkd.me.uk
16
32
  executables: []
@@ -18,12 +34,14 @@ extensions: []
18
34
  extra_rdoc_files: []
19
35
  files:
20
36
  - lib/quaff.rb
37
+ - lib/sip_parser.rb
38
+ - lib/message.rb
21
39
  - lib/utils.rb
22
40
  - lib/call.rb
23
- - lib/sources.rb
24
- - lib/sip_parser.rb
25
41
  - lib/endpoint.rb
26
- homepage: http://github.com/rkd91/quaff
42
+ - lib/auth.rb
43
+ - lib/sources.rb
44
+ homepage: http://github.com/rkday/quaff
27
45
  licenses:
28
46
  - GPL3
29
47
  post_install_message: