oversip 1.2.1 → 1.3.0.dev1

Sign up to get free protection for your applications and to get access to all the features.
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