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.
- data/README.md +28 -4
- data/bin/oversip +1 -1
- data/etc/proxies.conf +10 -0
- data/etc/server.rb +13 -9
- data/ext/utils/haproxy_protocol.c +0 -3
- data/ext/utils/outbound_utils.c +1 -1
- data/ext/utils/utils_ruby.c +0 -1
- data/ext/websocket_http_parser/ws_http_parser.c +940 -1903
- data/ext/websocket_http_parser/ws_http_parser.h +1 -0
- data/lib/oversip/config_validators.rb +2 -2
- data/lib/oversip/launcher.rb +275 -240
- data/lib/oversip/master_process.rb +7 -2
- data/lib/oversip/proxies_config.rb +8 -1
- data/lib/oversip/sip/client.rb +304 -0
- data/lib/oversip/sip/client_transaction.rb +31 -36
- data/lib/oversip/sip/core.rb +7 -4
- data/lib/oversip/sip/launcher.rb +30 -30
- data/lib/oversip/sip/listeners/connection.rb +4 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +1 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +1 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +1 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +1 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +1 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +1 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +1 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +1 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +26 -0
- data/lib/oversip/sip/listeners/tcp_connection.rb +7 -1
- data/lib/oversip/sip/listeners/tcp_server.rb +1 -1
- data/lib/oversip/sip/listeners/tls_client.rb +28 -24
- data/lib/oversip/sip/listeners/tls_server.rb +25 -8
- data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +1 -24
- data/lib/oversip/sip/message.rb +2 -2
- data/lib/oversip/sip/message_processor.rb +23 -13
- data/lib/oversip/sip/{grammar/name_addr.rb → name_addr.rb} +11 -0
- data/lib/oversip/sip/proxy.rb +53 -227
- data/lib/oversip/sip/request.rb +15 -11
- data/lib/oversip/sip/response.rb +3 -3
- data/lib/oversip/sip/rfc3263.rb +2 -3
- data/lib/oversip/sip/tags.rb +1 -1
- data/lib/oversip/sip/transport_manager.rb +6 -5
- data/lib/oversip/sip/uac.rb +93 -0
- data/lib/oversip/sip/uac_request.rb +82 -0
- data/lib/oversip/sip/{grammar/uri.rb → uri.rb} +22 -0
- data/lib/oversip/version.rb +3 -3
- data/lib/oversip/websocket/launcher.rb +25 -25
- data/lib/oversip/websocket/listeners/connection.rb +4 -0
- data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +1 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +1 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +1 -0
- data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +1 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +1 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +1 -0
- data/lib/oversip/websocket/listeners/ws_server.rb +55 -26
- data/lib/oversip/websocket/listeners/wss_server.rb +26 -9
- data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +14 -11
- data/lib/oversip/websocket/ws_framing.rb +6 -2
- data/lib/oversip.rb +3 -1
- data/test/test_http_parser.rb +3 -3
- data/test/test_uri.rb +18 -12
- metadata +91 -77
    
        data/lib/oversip/sip/proxy.rb
    CHANGED
    
    | @@ -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 #{@ | 
| 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, @ | 
| 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 | 
            -
                   | 
| 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 | 
            -
                   | 
| 158 | 
            -
                   | 
| 159 | 
            -
             | 
| 160 | 
            -
             | 
| 161 | 
            -
             | 
| 162 | 
            -
             | 
| 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 @ | 
| 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 | 
            -
                 | 
| 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 = @ | 
| 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 | 
            -
                         | 
| 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 | 
            -
                         | 
| 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  | 
| 359 | 
            -
                  #  | 
| 360 | 
            -
                   | 
| 361 | 
            -
             | 
| 362 | 
            -
             | 
| 363 | 
            -
             | 
| 364 | 
            -
             | 
| 365 | 
            -
             | 
| 366 | 
            -
             | 
| 367 | 
            -
             | 
| 368 | 
            -
                     | 
| 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 | 
            -
                  #  | 
| 283 | 
            +
                  # If not, generate the response according to the given status and reason.
         | 
| 396 284 | 
             
                  else
         | 
| 397 | 
            -
                     | 
| 398 | 
            -
                     | 
| 399 | 
            -
                      @ | 
| 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 | 
            -
                      @ | 
| 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  #  | 
| 293 | 
            +
                end  # no_more_targets
         | 
| 420 294 |  | 
| 421 295 |  | 
| 422 | 
            -
                def  | 
| 423 | 
            -
                   | 
| 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 | 
            -
                   | 
| 427 | 
            -
             | 
| 428 | 
            -
                   | 
| 429 | 
            -
                     | 
| 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
         | 
    
        data/lib/oversip/sip/request.rb
    CHANGED
    
    | @@ -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 <<  | 
| 56 | 
            +
                    response << "Via: " << hdr << CRLF
         | 
| 53 57 | 
             
                  end
         | 
| 54 58 |  | 
| 55 | 
            -
                  response << "From: " << @hdr_from <<  | 
| 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 <<  | 
| 63 | 
            +
                  response << CRLF
         | 
| 60 64 |  | 
| 61 | 
            -
                  response << "Call-ID: " << @call_id <<  | 
| 62 | 
            -
                  response << "CSeq: " << @cseq.to_s << " " << @sip_method.to_s <<  | 
| 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 <<  | 
| 70 | 
            +
                    response << header.to_s << CRLF
         | 
| 67 71 | 
             
                  end  if extra_headers
         | 
| 68 72 |  | 
| 69 | 
            -
                  response << HDR_SERVER <<  | 
| 70 | 
            -
                  response <<  | 
| 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 | | 
| 136 | 
            +
                  @headers.each do |name, values|
         | 
| 133 137 | 
             
                    values.each do |value|
         | 
| 134 | 
            -
                      msg <<  | 
| 138 | 
            +
                      msg << name << ": #{value}\r\n"
         | 
| 135 139 | 
             
                    end
         | 
| 136 140 | 
             
                  end
         | 
| 137 141 |  | 
    
        data/lib/oversip/sip/response.rb
    CHANGED
    
    | @@ -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 ] | 
| 21 | 
            +
                    @headers["To"] = [ hdr_to ]
         | 
| 22 22 | 
             
                  end
         | 
| 23 23 |  | 
| 24 | 
            -
                  @headers.each do | | 
| 24 | 
            +
                  @headers.each do |name, values|
         | 
| 25 25 | 
             
                    values.each do |value|
         | 
| 26 | 
            -
                      msg <<  | 
| 26 | 
            +
                      msg << name << ": #{value}\r\n"
         | 
| 27 27 | 
             
                    end
         | 
| 28 28 | 
             
                  end
         | 
| 29 29 |  | 
    
        data/lib/oversip/sip/rfc3263.rb
    CHANGED
    
    | @@ -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 : | 
| 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
         | 
    
        data/lib/oversip/sip/tags.rb
    CHANGED
    
    | @@ -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. | 
| 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  | 
| 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 | 
            -
                     | 
| 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 ( | 
| 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 | 
            -
                  #  | 
| 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
         |