oversip 1.2.1 → 1.3.0.dev1

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.
Files changed (61) hide show
  1. data/README.md +28 -4
  2. data/bin/oversip +1 -1
  3. data/etc/proxies.conf +10 -0
  4. data/etc/server.rb +13 -9
  5. data/ext/utils/haproxy_protocol.c +0 -3
  6. data/ext/utils/outbound_utils.c +1 -1
  7. data/ext/utils/utils_ruby.c +0 -1
  8. data/ext/websocket_http_parser/ws_http_parser.c +940 -1903
  9. data/ext/websocket_http_parser/ws_http_parser.h +1 -0
  10. data/lib/oversip/config_validators.rb +2 -2
  11. data/lib/oversip/launcher.rb +275 -240
  12. data/lib/oversip/master_process.rb +7 -2
  13. data/lib/oversip/proxies_config.rb +8 -1
  14. data/lib/oversip/sip/client.rb +304 -0
  15. data/lib/oversip/sip/client_transaction.rb +31 -36
  16. data/lib/oversip/sip/core.rb +7 -4
  17. data/lib/oversip/sip/launcher.rb +30 -30
  18. data/lib/oversip/sip/listeners/connection.rb +4 -0
  19. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +1 -0
  20. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +1 -0
  21. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +1 -0
  22. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +1 -0
  23. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +1 -0
  24. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +1 -0
  25. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +1 -0
  26. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +1 -0
  27. data/lib/oversip/sip/listeners/tcp_client.rb +26 -0
  28. data/lib/oversip/sip/listeners/tcp_connection.rb +7 -1
  29. data/lib/oversip/sip/listeners/tcp_server.rb +1 -1
  30. data/lib/oversip/sip/listeners/tls_client.rb +28 -24
  31. data/lib/oversip/sip/listeners/tls_server.rb +25 -8
  32. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +1 -24
  33. data/lib/oversip/sip/message.rb +2 -2
  34. data/lib/oversip/sip/message_processor.rb +23 -13
  35. data/lib/oversip/sip/{grammar/name_addr.rb → name_addr.rb} +11 -0
  36. data/lib/oversip/sip/proxy.rb +53 -227
  37. data/lib/oversip/sip/request.rb +15 -11
  38. data/lib/oversip/sip/response.rb +3 -3
  39. data/lib/oversip/sip/rfc3263.rb +2 -3
  40. data/lib/oversip/sip/tags.rb +1 -1
  41. data/lib/oversip/sip/transport_manager.rb +6 -5
  42. data/lib/oversip/sip/uac.rb +93 -0
  43. data/lib/oversip/sip/uac_request.rb +82 -0
  44. data/lib/oversip/sip/{grammar/uri.rb → uri.rb} +22 -0
  45. data/lib/oversip/version.rb +3 -3
  46. data/lib/oversip/websocket/launcher.rb +25 -25
  47. data/lib/oversip/websocket/listeners/connection.rb +4 -0
  48. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +1 -0
  49. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +1 -0
  50. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +1 -0
  51. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +1 -0
  52. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +1 -0
  53. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +1 -0
  54. data/lib/oversip/websocket/listeners/ws_server.rb +55 -26
  55. data/lib/oversip/websocket/listeners/wss_server.rb +26 -9
  56. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +14 -11
  57. data/lib/oversip/websocket/ws_framing.rb +6 -2
  58. data/lib/oversip.rb +3 -1
  59. data/test/test_http_parser.rb +3 -3
  60. data/test/test_uri.rb +18 -12
  61. metadata +91 -77
@@ -1,62 +1,19 @@
1
1
  module OverSIP::SIP
2
2
 
3
- class Proxy
4
-
5
- include ::OverSIP::Logger
6
-
7
- def initialize proxy_profile=:default_proxy
8
- unless (@proxy_conf = ::OverSIP.proxies[proxy_profile.to_sym])
9
- raise ::OverSIP::RuntimeError, "proxy '#{proxy_profile}' is not defined in Proxies Configuration file"
10
- end
11
- end
12
-
13
-
14
- def on_provisional_response &block
15
- @on_provisional_response_block = block
16
- end
17
-
18
- def on_success_response &block
19
- @on_success_response_block = block
20
- end
21
-
22
- def on_failure_response &block
23
- @on_failure_response_block = block
24
- end
25
-
26
- def on_canceled &block
27
- @on_canceled_block = block
28
- end
29
-
30
- def on_invite_timeout &block
31
- @on_invite_timeout_block = block
32
- end
33
-
34
- def on_error &block
35
- @on_error_block = block
36
- end
37
-
38
- def on_target &block
39
- @on_target_block = block
40
- end
3
+ class Proxy < Client
41
4
 
42
5
  # If called, current response within the called callback won't be forwarded.
43
6
  def drop_response
44
7
  @drop_response = true
45
8
  end
46
9
 
47
- # It must only be called within the on_target() callback. By calling this method,
48
- # the request routing is aborted, no more DNS targets are tryed, a local 403 response
49
- # is generated and on_error() callback is called with status 403.
50
- def abort_routing
51
- @aborted = true
52
- end
53
10
 
54
11
  def route request, dst_host=nil, dst_port=nil, dst_transport=nil
55
12
  unless (@request = request).is_a? ::OverSIP::SIP::Request
56
13
  raise ::OverSIP::RuntimeError, "request must be a OverSIP::SIP::Request instance"
57
14
  end
58
15
 
59
- @log_id = "Proxy #{@proxy_conf[:name]} #{@request.via_branch_id}"
16
+ @log_id = "Proxy #{@conf[:name]} #{@request.via_branch_id}"
60
17
 
61
18
  # Create the server transaction if it doesn't exist yet.
62
19
  @server_transaction = @request.server_transaction or case @request.sip_method
@@ -79,7 +36,7 @@ module OverSIP::SIP
79
36
  # set then don't honor the Outbound connection).
80
37
 
81
38
  if @request.incoming_outbound_requested? and not dst_host
82
- @client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @proxy_conf, @request.route_outbound_flow_token
39
+ @client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @conf, @request.route_outbound_flow_token
83
40
 
84
41
  if @client_transaction.connection
85
42
  add_routing_headers
@@ -88,7 +45,7 @@ module OverSIP::SIP
88
45
  unless @request.sip_method == :ACK
89
46
  log_system_debug "flow failed" if $oversip_debug
90
47
 
91
- @on_error_block && @on_error_block.call(430, "Flow Failed")
48
+ @on_error_block && @on_error_block.call(430, "Flow Failed", :flow_failed)
92
49
  unless @drop_response
93
50
  @request.reply 430, "Flow Failed"
94
51
  else
@@ -139,56 +96,14 @@ module OverSIP::SIP
139
96
  end
140
97
 
141
98
  # Loockup in the DNS cache of this proxy.
142
- if dst_host_type == :domain and @proxy_conf[:use_dns_cache]
143
- dns_cache_entry = "#{dst_host}|#{dst_port}|#{dst_transport}|#{dst_scheme}"
144
- if (result = @proxy_conf[:dns_cache][dns_cache_entry])
145
- log_system_debug "destination found in the DNS cache" if $oversip_debug
146
- if result.is_a? ::Symbol
147
- rfc3263_failed result
148
- else
149
- rfc3263_succeeded result
150
- end
151
- return
152
- end
153
- else
154
- dns_cache_entry = nil
155
- end
99
+ result = check_dns_cache dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
156
100
 
157
- # Perform RFC 3261 procedures.
158
- dns_query = ::OverSIP::SIP::RFC3263::Query.new @proxy_conf, @request.via_branch_id, dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
159
- case result = dns_query.resolve
160
-
161
- # Async result so DNS took place.
162
- when nil
163
- # Async success.
164
- dns_query.callback do |result|
165
- # Store the result in the DNS cache.
166
- if dns_cache_entry
167
- @proxy_conf[:dns_cache][dns_cache_entry] = result
168
- ::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
169
- end
170
- rfc3263_succeeded result
171
- end
172
- # Async error.
173
- dns_query.errback do |result|
174
- # Store the result in the DNS cache.
175
- if dns_cache_entry
176
- @proxy_conf[:dns_cache][dns_cache_entry] = result
177
- ::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
178
- end
179
- rfc3263_failed result
180
- end
181
- # Instant error.
182
- when ::Symbol
183
- # Store the result in the DNS cache.
184
- if dns_cache_entry
185
- @proxy_conf[:dns_cache][dns_cache_entry] = result
186
- ::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
187
- end
188
- rfc3263_failed result
189
- # Instant success so it's not a domain (no DNS performed).
190
- else
191
- rfc3263_succeeded result
101
+ case result
102
+ when true
103
+ return
104
+ else # It can be String or nil, so use it as dns_cache_key param.
105
+ # Perform RFC 3263 procedures.
106
+ do_dns result, @request.via_branch_id, dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
192
107
  end
193
108
 
194
109
  end # def route
@@ -206,7 +121,7 @@ module OverSIP::SIP
206
121
  @on_success_response_block && @on_success_response_block.call(response)
207
122
  elsif response.status_code >= 300 && ! @canceled
208
123
  if response.status_code == 503
209
- if @proxy_conf[:dns_failover_on_503]
124
+ if @conf[:dns_failover_on_503]
210
125
  try_next_target nil, nil, response
211
126
  return
212
127
  else
@@ -239,22 +154,7 @@ module OverSIP::SIP
239
154
  end
240
155
 
241
156
 
242
- def client_timeout
243
- try_next_target 408, "Client Timeout"
244
- end
245
-
246
-
247
- def connection_failed
248
- try_next_target 500, "Connection Error"
249
- end
250
-
251
-
252
- def tls_validation_failed
253
- try_next_target 500, "TLS Validation Failed"
254
- end
255
-
256
-
257
- # Timer C for INVITE.
157
+ # Timer C for INVITE (method called by the client transaction).
258
158
  def invite_timeout
259
159
  @on_invite_timeout_block && @on_invite_timeout_block.call
260
160
 
@@ -265,6 +165,7 @@ module OverSIP::SIP
265
165
  end
266
166
 
267
167
 
168
+
268
169
  private
269
170
 
270
171
 
@@ -278,7 +179,7 @@ module OverSIP::SIP
278
179
 
279
180
  # NOTE: As per RFC 6665 the proxy MUST add Record-Route to in-dialog NOTIFY's.
280
181
  if (@request.initial? and @request.record_routing_aware?) or @request.sip_method == :NOTIFY
281
- do_record_routing = @proxy_conf[:do_record_routing]
182
+ do_record_routing = @conf[:do_record_routing]
282
183
 
283
184
  # Request has no previous RR/Path and current proxy performs record-routing.
284
185
  # So add RR/Path.
@@ -329,7 +230,13 @@ module OverSIP::SIP
329
230
  @request.insert_header "Path", @request.connection.class.record_route
330
231
  else
331
232
  @request.in_rr = :path
332
- @request.insert_header "Path", @request.connection.class.record_route
233
+ # The request comes via UDP or via a connection made by the client.
234
+ if @request.connection.class.outbound_listener?
235
+ @request.insert_header "Path", @request.connection.class.record_route
236
+ # The request comes via a TCP/TLS connection made by OverSIP.
237
+ else
238
+ @request.insert_header "Path", @request.connection.record_route
239
+ end
333
240
  end
334
241
 
335
242
  # Record-Route for INVITE, SUBSCRIBE, REFER and in-dialog NOTIFY.
@@ -346,7 +253,13 @@ module OverSIP::SIP
346
253
  @request.insert_header "Record-Route", @request.connection.class.record_route
347
254
  else
348
255
  @request.in_rr = :rr
349
- @request.insert_header "Record-Route", @request.connection.class.record_route
256
+ # The request comes via UDP or via a connection made by the client.
257
+ if @request.connection.class.outbound_listener?
258
+ @request.insert_header "Record-Route", @request.connection.class.record_route
259
+ # The request comes via a TCP/TLS connection made by OverSIP.
260
+ else
261
+ @request.insert_header "Record-Route", @request.connection.record_route
262
+ end
350
263
  end
351
264
 
352
265
  end
@@ -355,129 +268,42 @@ module OverSIP::SIP
355
268
  end # add_routing_headers
356
269
 
357
270
 
358
- def rfc3263_succeeded result
359
- # After RFC 3263 (DNS) resolution we get N targets.
360
- @num_target = 0 # First target is 0 (rather than 1).
361
-
362
- case result
363
-
364
- when RFC3263::Target
365
- @target = result # Single Target.
366
-
367
- when RFC3263::SrvTargets
368
- log_system_debug "result is srv targets => randomizing:" if $oversip_debug
369
- @targets = result.randomize # Array of Targets.
370
-
371
- # This can contain Target and SrvTargets entries.
372
- when RFC3263::MultiTargets
373
- log_system_debug "result is MultiTargets => flatting:" if $oversip_debug
374
- @targets = result.flatten # Array of Targets.
375
-
376
- end
377
-
378
- try_next_target
379
- end # rfc3263_succeeded
380
-
381
-
382
- def try_next_target status=nil, reason=nil, full_response=nil
383
- # Single target.
384
- if @target and @num_target == 0
385
- log_system_debug "using single target: #{@target}" if $oversip_debug
386
- use_target @target
387
- @num_target = 1
388
-
389
- # Multiple targets (so @targets is set).
390
- elsif @targets and @num_target < @targets.size
391
- log_system_debug "using target #{@num_target+1} of #{@targets.size}: #{@targets[@num_target]}" if $oversip_debug
392
- use_target @targets[@num_target]
393
- @num_target += 1
271
+ def no_more_targets status, reason, full_response, code
272
+ # If we have received a [3456]XX response from downstream then run @on_failure_block.
273
+ if full_response
274
+ @on_failure_response_block && @on_failure_response_block.call(full_response)
275
+ unless @drop_response
276
+ # If the response is 503 convert it into 500 (RFC 3261 16.7).
277
+ full_response.status_code = 500 if full_response.status_code == 503
278
+ @request.reply_full full_response
279
+ else
280
+ @drop_response = false
281
+ end
394
282
 
395
- # No more targets.
283
+ # If not, generate the response according to the given status and reason.
396
284
  else
397
- # If we have received a [3456]XX response from downstream then run @on_failure_block.
398
- if full_response
399
- @on_failure_response_block && @on_failure_response_block.call(full_response)
400
- unless @drop_response
401
- # If the response is 503 convert it into 500 (RFC 3261 16.7).
402
- full_response.status_code = 500 if full_response.status_code == 503
403
- @request.reply_full full_response
404
- else
405
- @drop_response = false
406
- end
407
-
408
- # If not, generate the response according to the given status and reason.
285
+ @on_error_block && @on_error_block.call(status, reason, code)
286
+ unless @drop_response
287
+ @request.reply status, reason
409
288
  else
410
- @on_error_block && @on_error_block.call(status, reason)
411
- unless @drop_response
412
- @request.reply status, reason
413
- else
414
- @drop_response = false
415
- end
416
-
289
+ @drop_response = false
417
290
  end
291
+
418
292
  end
419
- end # try_next_target
293
+ end # no_more_targets
420
294
 
421
295
 
422
- def use_target target
423
- # Call the on_target() callback if set by the user.
424
- @on_target_block && @on_target_block.call(target.ip_type, target.ip, target.port, target.transport)
296
+ def do_dns_fail status, reason, code
297
+ @on_error_block && @on_error_block.call(status, reason, code)
425
298
 
426
- # If the user has called to proxy.abort_routing() then stop next targets
427
- # and call to on_error() callback.
428
- if @aborted
429
- log_system_notice "routing aborted for target #{target}"
430
- @aborted = @target = @targets = nil
431
- try_next_target 403, "Destination Not Allowed"
432
- return
299
+ unless @drop_response
300
+ @request.reply status, reason unless @request.sip_method == :ACK
301
+ else
302
+ @drop_response = false
433
303
  end
434
-
435
- @client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @proxy_conf, target.transport, target.ip, target.ip_type, target.port
436
- add_routing_headers
437
- @client_transaction.send_request
438
304
  end
439
305
 
440
306
 
441
- def rfc3263_failed error
442
- case error
443
- when :rfc3263_domain_not_found
444
- log_system_debug "no resolution" if $oversip_debug
445
- status = 404
446
- reason = "No DNS Resolution"
447
- when :rfc3263_unsupported_scheme
448
- log_system_debug "unsupported URI scheme" if $oversip_debug
449
- status = 416
450
- reason = "Unsupported URI scheme"
451
- when :rfc3263_unsupported_transport
452
- log_system_debug "unsupported transport" if $oversip_debug
453
- status = 478
454
- reason = "Unsupported Transport"
455
- when :rfc3263_wrong_transport
456
- log_system_debug "wrong URI transport" if $oversip_debug
457
- status = 478
458
- reason = "Wrong URI Transport"
459
- when :rfc3263_no_ipv4
460
- log_system_debug "destination requires unsupported IPv4" if $oversip_debug
461
- status = 478
462
- reason = "Destination Requires Unsupported IPv4"
463
- when :rfc3263_no_ipv6
464
- log_system_debug "destination requires unsupported IPv6" if $oversip_debug
465
- status = 478
466
- reason = "Destination Requires Unsupported IPv6"
467
- when :rfc3263_no_dns
468
- log_system_debug "destination requires unsupported DNS query" if $oversip_debug
469
- status = 478
470
- reason = "Destination Requires Unsupported DNS Query"
471
- end
472
-
473
- @on_error_block && @on_error_block.call(status, reason)
474
- unless @drop_response
475
- @request.reply status, reason unless @request.sip_method == :ACK
476
- else
477
- @drop_response = false
478
- end
479
- end # def rfc3263_failed
480
-
481
307
  end # class Proxy
482
308
 
483
309
  end
@@ -38,36 +38,40 @@ module OverSIP::SIP
38
38
 
39
39
 
40
40
  def reply status_code, reason_phrase=nil, extra_headers=[], body=nil
41
+ if @sip_method == :ACK
42
+ log_system_error "attemtp to reply to an ACK aborted"
43
+ return false
44
+ end
41
45
  return false unless @server_transaction.receive_response(status_code) if @server_transaction
42
46
 
43
47
  reason_phrase ||= REASON_PHARSE[status_code] || REASON_PHARSE_NOT_SET
44
48
 
45
49
  if status_code > 100
46
- @internal_to_tag ||= @to_tag || ( @server_transaction ? SecureRandom.hex(6) : OverSIP::SIP::Tags.totag_for_sl_reply )
50
+ @internal_to_tag ||= @to_tag || ( @server_transaction ? ::SecureRandom.hex(6) : ::OverSIP::SIP::Tags.totag_for_sl_reply )
47
51
  end
48
52
 
49
53
  response = "SIP/2.0 #{status_code} #{reason_phrase}\r\n"
50
54
 
51
55
  @hdr_via.each do |hdr|
52
- response << "Via: " << hdr << "\r\n"
56
+ response << "Via: " << hdr << CRLF
53
57
  end
54
58
 
55
- response << "From: " << @hdr_from << "\r\n"
59
+ response << "From: " << @hdr_from << CRLF
56
60
 
57
61
  response << "To: " << @hdr_to
58
62
  response << ";tag=#{@internal_to_tag}" if @internal_to_tag
59
- response << "\r\n"
63
+ response << CRLF
60
64
 
61
- response << "Call-ID: " << @call_id << "\r\n"
62
- response << "CSeq: " << @cseq.to_s << " " << @sip_method.to_s << "\r\n"
65
+ response << "Call-ID: " << @call_id << CRLF
66
+ response << "CSeq: " << @cseq.to_s << " " << @sip_method.to_s << CRLF
63
67
  response << "Content-Length: #{body ? body.bytesize : "0"}\r\n"
64
68
 
65
69
  extra_headers.each do |header|
66
- response << header.to_s << "\r\n"
70
+ response << header.to_s << CRLF
67
71
  end if extra_headers
68
72
 
69
- response << HDR_SERVER << "\r\n"
70
- response << "\r\n"
73
+ response << HDR_SERVER << CRLF
74
+ response << CRLF
71
75
 
72
76
  response << body if body
73
77
 
@@ -129,9 +133,9 @@ module OverSIP::SIP
129
133
  @headers["Contact"] = [ @contact.to_s << (@contact_params ? @contact_params : "") ]
130
134
  end
131
135
 
132
- @headers.each do |key, values|
136
+ @headers.each do |name, values|
133
137
  values.each do |value|
134
- msg << key << ": #{value}\r\n"
138
+ msg << name << ": #{value}\r\n"
135
139
  end
136
140
  end
137
141
 
@@ -18,12 +18,12 @@ module OverSIP::SIP
18
18
  @headers["From"] = [ request.hdr_from ] if request.from_was_modified
19
19
  if request.to_was_modified
20
20
  hdr_to = @to_tag ? "#{request.hdr_to};tag=#{@to_tag}" : request.hdr_to
21
- @headers["To"] = [ hdr_to ] if request.to_was_modified
21
+ @headers["To"] = [ hdr_to ]
22
22
  end
23
23
 
24
- @headers.each do |key, values|
24
+ @headers.each do |name, values|
25
25
  values.each do |value|
26
- msg << key << ": #{value}\r\n"
26
+ msg << name << ": #{value}\r\n"
27
27
  end
28
28
  end
29
29
 
@@ -216,7 +216,7 @@ module OverSIP::SIP
216
216
  dns_transport = :udp
217
217
  # "sips" is not possible in UDP.
218
218
  else
219
- return :rfc3263_wrong_transport
219
+ return :rfc3263_unsupported_transport
220
220
  end
221
221
  when :tcp
222
222
  case (dns_transport = ( @uri_scheme == :sips ? :tls : :tcp ))
@@ -271,7 +271,6 @@ module OverSIP::SIP
271
271
  elsif @uri_transport
272
272
  if @use_srv
273
273
  if (targets = resolve_SRV(@uri_host, @uri_scheme, dns_transport))
274
- ### TODO: Esto es nuevo para mejora. Antes devolvía siempre el segundo caso.
275
274
  if targets.size == 1
276
275
  @on_success_block && @on_success_block.call(targets[0])
277
276
  else
@@ -415,7 +414,7 @@ module OverSIP::SIP
415
414
 
416
415
  end
417
416
 
418
- end
417
+ end # @@fiber_pool.spawn
419
418
 
420
419
  nil
421
420
  end
@@ -31,7 +31,7 @@ module OverSIP::SIP
31
31
 
32
32
  def self.create_antiloop_id request
33
33
  # It produces a 32 chars string.
34
- ::Digest::MD5.hexdigest "#{ANTILOOP_CONST}#{request.ruri.uri}#{request.call_id}#{request.routes[0].uri if request.routes}"
34
+ ::Digest::MD5.hexdigest "#{ANTILOOP_CONST}#{request.ruri.to_s}#{request.call_id}#{request.routes[0].uri if request.routes}"
35
35
  end
36
36
 
37
37
  end
@@ -9,7 +9,7 @@ module OverSIP::SIP
9
9
 
10
10
 
11
11
  # Get an existing connection or create a new one (TCP/TLS).
12
- # For UDP it always return the single UDP reactor instance.
12
+ # For UDP it always returns the single UDP reactor instance.
13
13
  # client_transaction is passed when creating a new clien transaction. In case the
14
14
  # outgoing connection is a TCP/TLS client connection and it's not connected yet,
15
15
  # the client transaction is stored in the @pending_client_transactions of the client
@@ -62,9 +62,10 @@ module OverSIP::SIP
62
62
 
63
63
  # NOTE: Should never happen.
64
64
  unless conn
65
- log_system_error "no connection (nil) retrieved from TransportManager.get_connection(), FIXME, it should never occur!!!"
66
- raise "no connection (nil) retrieved from TransportManager.get_connection(), FIXME, it should never occur!!!"
65
+ ::OverSIP::Launcher.fatal "no connection retrieved from TransportManager.get_connection(), FIXME, it should never occur!!!"
67
66
  end
67
+
68
+ # Return the created/retrieved connection instance.
68
69
  conn
69
70
  end
70
71
 
@@ -92,7 +93,7 @@ module OverSIP::SIP
92
93
  if flow_token.getbyte(0) == 95
93
94
  # NOTE: Doing Base64.decode64 automatically removes the leading "_".
94
95
  # NOTE: Previously when the Outbound flow token was generated, "=" was replaced with "-" so it becomes
95
- # valid for a SIP URI param (in case of using Contact mangling if the registrar does not support Path).
96
+ # valid for a SIP URI param (needed i.e. for the OutboundMangling module).
96
97
  ip_type, ip, port = ::OverSIP::Utils.parse_outbound_udp_flow_token(::Base64.decode64 flow_token.gsub(/-/,"="))
97
98
 
98
99
  case ip_type
@@ -105,7 +106,7 @@ module OverSIP::SIP
105
106
  return false
106
107
  end
107
108
 
108
- # It not, the flow token has been generated for a TCP/TLS/WS/WSS connection so let's lookup
109
+ # If not, the flow token has been generated for a TCP/TLS/WS/WSS connection so let's lookup
109
110
  # it into the Outbound connection collection and return nil for IP and port.
110
111
  else
111
112
  @outbound_connections[flow_token]
@@ -0,0 +1,93 @@
1
+ module OverSIP::SIP
2
+
3
+ class Uac < Client
4
+
5
+
6
+ def route request, dst_host=nil, dst_port=nil, dst_transport=nil
7
+ unless (@request = request).is_a? ::OverSIP::SIP::UacRequest or @request.is_a? ::OverSIP::SIP::Request
8
+ raise ::OverSIP::RuntimeError, "request must be a OverSIP::SIP::UacRequest or OverSIP::SIP::Request instance"
9
+ end
10
+
11
+ # The destination of the request is taken from:
12
+ # - dst_xxx fields if given.
13
+ # - The request.ruri if it is an OverSIP::SIP::Uri or OverSIP::SIP::NameAddr.
14
+ # Otherwise raise an exception.
15
+ unless dst_host or request.ruri.is_a?(::OverSIP::SIP::Uri) or request.ruri.is_a?(::OverSIP::SIP::NameAddr)
16
+ raise ::OverSIP::RuntimeError, "if dst_host is not given then request.ruri must be an OverSIP::SIP::Uri or OverSIP::SIP::NameAddr instance"
17
+ end
18
+
19
+ @log_id = "UAC (proxy #{@conf[:name]})"
20
+
21
+ # Force the destination.
22
+ if dst_host
23
+ dst_scheme = :sip
24
+ dst_host_type = ::OverSIP::Utils.ip_type(dst_host) || :domain
25
+
26
+ # Or use the Request URI.
27
+ else
28
+ dst_scheme = request.ruri.scheme
29
+ dst_host = request.ruri.host
30
+ dst_host_type = request.ruri.host_type
31
+ dst_port = request.ruri.port
32
+ dst_transport = request.ruri.transport_param
33
+ end
34
+
35
+ # If the destination uri_host is an IPv6 reference, convert it to real IPv6.
36
+ if dst_host_type == :ipv6_reference
37
+ dst_host = ::OverSIP::Utils.normalize_ipv6(dst_host, true)
38
+ dst_host_type = :ipv6
39
+ end
40
+
41
+ # Loockup in the DNS cache of this proxy.
42
+ result = check_dns_cache dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
43
+
44
+ case result
45
+ when true
46
+ return
47
+ else # It can be String or nil, so use it as dns_cache_key param.
48
+ # Perform RFC 3263 procedures.
49
+ do_dns result, @request.via_branch_id, dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
50
+ end
51
+
52
+ end # def send
53
+
54
+
55
+ def receive_response response
56
+ log_system_debug "received response #{response.status_code}" if $oversip_debug
57
+
58
+ if response.status_code < 200
59
+ @on_provisional_response_block && @on_provisional_response_block.call(response)
60
+ elsif response.status_code >= 200 && response.status_code <= 299
61
+ @on_success_response_block && @on_success_response_block.call(response)
62
+ elsif response.status_code >= 300
63
+ if response.status_code == 503
64
+ if @conf[:dns_failover_on_503]
65
+ try_next_target nil, nil, response
66
+ return
67
+ else
68
+ @on_failure_response_block && @on_failure_response_block.call(response)
69
+ end
70
+ else
71
+ @on_failure_response_block && @on_failure_response_block.call(response)
72
+ end
73
+ end
74
+ end
75
+
76
+
77
+
78
+ private
79
+
80
+
81
+ def no_more_targets status, reason, full_response, code
82
+ # If we have received a [3456]XX response from downstream then run @on_failure_block.
83
+ if full_response
84
+ @on_failure_response_block && @on_failure_response_block.call(full_response)
85
+ # If not, generate the response according to the given status and reason.
86
+ else
87
+ @on_error_block && @on_error_block.call(status, reason, code)
88
+ end
89
+ end
90
+
91
+ end # class Uac
92
+
93
+ end