oversip_p 1.0.0

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 (132) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +22 -0
  3. data/LICENSE +25 -0
  4. data/README.md +43 -0
  5. data/Rakefile +54 -0
  6. data/bin/oversip +184 -0
  7. data/etc/oversip.conf +274 -0
  8. data/etc/proxies.conf +145 -0
  9. data/etc/server.rb +315 -0
  10. data/etc/tls/ca/cacert.pem +3894 -0
  11. data/etc/tls/demo-tls.oversip.net.crt +17 -0
  12. data/etc/tls/demo-tls.oversip.net.key +15 -0
  13. data/etc/tls/upgrade-cacert.sh +12 -0
  14. data/etc/tls/utils/create-cert.rb +162 -0
  15. data/etc/tls/utils/get-sip-identities.rb +95 -0
  16. data/ext/common/c_util.h +74 -0
  17. data/ext/common/ruby_c_util.h +88 -0
  18. data/ext/sip_parser/common_headers.h +210 -0
  19. data/ext/sip_parser/ext_help.h +18 -0
  20. data/ext/sip_parser/extconf.rb +3 -0
  21. data/ext/sip_parser/sip_message_parser.c +29741 -0
  22. data/ext/sip_parser/sip_parser.h +250 -0
  23. data/ext/sip_parser/sip_parser_ruby.c +1370 -0
  24. data/ext/sip_parser/sip_uri_parser.c +39699 -0
  25. data/ext/stud/extconf.rb +43 -0
  26. data/ext/stun/ext_help.h +16 -0
  27. data/ext/stun/extconf.rb +3 -0
  28. data/ext/stun/stun_ruby.c +394 -0
  29. data/ext/utils/ext_help.h +14 -0
  30. data/ext/utils/extconf.rb +3 -0
  31. data/ext/utils/haproxy_protocol.c +6163 -0
  32. data/ext/utils/haproxy_protocol.h +27 -0
  33. data/ext/utils/ip_utils.c +5952 -0
  34. data/ext/utils/ip_utils.h +64 -0
  35. data/ext/utils/outbound_utils.c +3227 -0
  36. data/ext/utils/outbound_utils.h +27 -0
  37. data/ext/utils/utils_ruby.c +392 -0
  38. data/ext/utils/utils_ruby.h +76 -0
  39. data/ext/websocket_framing_utils/ext_help.h +18 -0
  40. data/ext/websocket_framing_utils/extconf.rb +3 -0
  41. data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
  42. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  43. data/ext/websocket_http_parser/ext_help.h +18 -0
  44. data/ext/websocket_http_parser/extconf.rb +3 -0
  45. data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
  46. data/ext/websocket_http_parser/ws_http_parser.h +87 -0
  47. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  48. data/lib/oversip/config.rb +597 -0
  49. data/lib/oversip/config_validators.rb +126 -0
  50. data/lib/oversip/default_server.rb +52 -0
  51. data/lib/oversip/errors.rb +10 -0
  52. data/lib/oversip/fiber_pool.rb +56 -0
  53. data/lib/oversip/launcher.rb +635 -0
  54. data/lib/oversip/logger.rb +84 -0
  55. data/lib/oversip/modules/outbound_mangling.rb +56 -0
  56. data/lib/oversip/modules/user_assertion.rb +73 -0
  57. data/lib/oversip/proxies_config.rb +189 -0
  58. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  59. data/lib/oversip/sip/client.rb +428 -0
  60. data/lib/oversip/sip/client_transaction.rb +586 -0
  61. data/lib/oversip/sip/constants.rb +88 -0
  62. data/lib/oversip/sip/core.rb +217 -0
  63. data/lib/oversip/sip/launcher.rb +221 -0
  64. data/lib/oversip/sip/listeners/connection.rb +54 -0
  65. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  66. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
  67. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  68. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
  69. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
  70. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
  71. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  72. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
  73. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  74. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
  75. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
  76. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
  77. data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
  78. data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
  79. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  80. data/lib/oversip/sip/listeners/tls_client.rb +125 -0
  81. data/lib/oversip/sip/listeners/tls_server.rb +88 -0
  82. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
  83. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  84. data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
  85. data/lib/oversip/sip/listeners.rb +24 -0
  86. data/lib/oversip/sip/message.rb +177 -0
  87. data/lib/oversip/sip/message_processor.rb +213 -0
  88. data/lib/oversip/sip/name_addr.rb +51 -0
  89. data/lib/oversip/sip/proxy.rb +324 -0
  90. data/lib/oversip/sip/request.rb +179 -0
  91. data/lib/oversip/sip/response.rb +37 -0
  92. data/lib/oversip/sip/rfc3263.rb +643 -0
  93. data/lib/oversip/sip/server_transaction.rb +295 -0
  94. data/lib/oversip/sip/sip.rb +76 -0
  95. data/lib/oversip/sip/tags.rb +39 -0
  96. data/lib/oversip/sip/timers.rb +55 -0
  97. data/lib/oversip/sip/transport_manager.rb +130 -0
  98. data/lib/oversip/sip/uac.rb +89 -0
  99. data/lib/oversip/sip/uac_request.rb +84 -0
  100. data/lib/oversip/sip/uri.rb +208 -0
  101. data/lib/oversip/syslog.rb +68 -0
  102. data/lib/oversip/system_callbacks.rb +45 -0
  103. data/lib/oversip/tls.rb +172 -0
  104. data/lib/oversip/utils.rb +30 -0
  105. data/lib/oversip/version.rb +21 -0
  106. data/lib/oversip/websocket/constants.rb +55 -0
  107. data/lib/oversip/websocket/http_request.rb +59 -0
  108. data/lib/oversip/websocket/launcher.rb +183 -0
  109. data/lib/oversip/websocket/listeners/connection.rb +51 -0
  110. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
  111. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
  112. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
  113. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
  114. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
  115. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
  116. data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
  117. data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
  118. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
  119. data/lib/oversip/websocket/listeners.rb +13 -0
  120. data/lib/oversip/websocket/websocket.rb +13 -0
  121. data/lib/oversip/websocket/ws_framing.rb +545 -0
  122. data/lib/oversip/websocket/ws_sip_app.rb +120 -0
  123. data/lib/oversip.rb +127 -0
  124. data/test/oversip_test_helper.rb +19 -0
  125. data/test/test_http_parser.rb +73 -0
  126. data/test/test_name_addr.rb +27 -0
  127. data/test/test_name_addr_parser.rb +24 -0
  128. data/test/test_sip_message_parser.rb +168 -0
  129. data/test/test_sip_uri_parser.rb +56 -0
  130. data/test/test_uri.rb +68 -0
  131. data/thirdparty/stud/stud.tar.gz +0 -0
  132. metadata +334 -0
@@ -0,0 +1,213 @@
1
+ module OverSIP::SIP
2
+
3
+ module MessageProcessor
4
+
5
+ # Constants for efficiency.
6
+ MSG_TYPE = {
7
+ ::OverSIP::SIP::Request => "SIP request",
8
+ ::OverSIP::SIP::Response => "SIP response",
9
+ :outbound_keepalive => "Outbound keepalive"
10
+ }
11
+
12
+
13
+ def valid_message? parser
14
+ if header = parser.missing_core_header?
15
+ log_system_notice "ignoring #{MSG_TYPE[@msg.class]} missing #{header} header"
16
+ return false
17
+ elsif header = parser.duplicated_core_header?
18
+ log_system_notice "ignoring #{MSG_TYPE[@msg.class]} with duplicated #{header} header"
19
+ return false
20
+ end
21
+ return true
22
+ end
23
+ private :valid_message?
24
+
25
+
26
+ # Via ;received and ;rport stuff.
27
+ def add_via_received_rport
28
+ # - If ;rport is present ;received MUST also be set (RFC 3581).
29
+ # - If not add ;received according to RFC 3261 rules.
30
+ if @msg.via_rport?
31
+ via_received = @msg.source_ip
32
+ @msg.via_rport = @msg.source_port
33
+ else
34
+ via_received = (::OverSIP::Utils.compare_ips(@msg.via_sent_by_host, @msg.source_ip) ? nil : @msg.source_ip)
35
+ end
36
+
37
+ if via_received
38
+ via_params = ";branch=" << @msg.via_branch if @msg.via_branch
39
+ via_params << ";received=" << via_received if via_received
40
+ via_params << ";rport=" << @msg.via_rport.to_s if @msg.via_rport
41
+ via_params << ";alias" if @msg.via_alias?
42
+
43
+ if @msg.via_params
44
+ @msg.via_params.each { |k,v| via_params << ( v ? ";#{k}=#{v}" : ";#{k}" ) }
45
+ end
46
+
47
+ @msg.hdr_via[0] = "#{@msg.via_core_value}#{via_params}"
48
+ end
49
+ end
50
+ private :add_via_received_rport
51
+
52
+
53
+ # Reject the message in case it doesn't contain a Via branch compliant with RFC 3261
54
+ def check_via_branch
55
+ if @msg.via_branch_rfc3261
56
+ @msg.via_branch_id = @msg.via_branch[7..-1] # The branch without "z9hG4bK".
57
+ return true
58
+ end
59
+
60
+ if @msg.is_a? Request
61
+ unless @msg.sip_method == :ACK
62
+ log_system_notice "request doesn't contain a RFC 3261 Via branch => 400"
63
+ @msg.reply 400, "Via branch non RFC 3261 compliant"
64
+ else
65
+ log_system_notice "ACK doesn't contain a RFC 3261 Via branch, ignoring it"
66
+ end
67
+ else
68
+ log_system_notice "response doesn't contain a RFC 3261 Via branch, ignoring it"
69
+ end
70
+ false
71
+ end
72
+ private :check_via_branch
73
+
74
+
75
+ def process_request
76
+ # Run the user provided OverSIP::SipEvents.on_request() callback (unless the request
77
+ # it's a retransmission, a CANCEL or an ACK for a final non-2XX response).
78
+ unless check_transaction
79
+ # Check OverSIP status.
80
+ unless ::OverSIP.status == :running
81
+ case ::OverSIP.status
82
+ when :loading
83
+ @msg.reply 500, "Server Still Loading", [ "Retry-After: 5" ]
84
+ when :terminating
85
+ @msg.reply 500, "Server is Being Stopped"
86
+ end
87
+ return
88
+ end
89
+
90
+ # Create the antiloop identifier for this request.
91
+ @msg.antiloop_id = ::OverSIP::SIP::Tags.create_antiloop_id(@msg)
92
+
93
+ # Check loops.
94
+ if @msg.antiloop_id == @msg.via_branch_id[-32..-1]
95
+ @msg.reply 482, "Loop Detected"
96
+ return
97
+ end
98
+
99
+ # Initialize some attributes for the request.
100
+ @msg.tvars = {}
101
+ @msg.cvars = @msg.connection.cvars
102
+
103
+ # Run OverSIP::SipEvents.on_request within a fiber.
104
+ ::Fiber.new do
105
+ begin
106
+ ::OverSIP::SipEvents.on_request @msg
107
+ rescue ::Exception => e
108
+ log_system_error "error calling OverSIP::SipEvents.on_request() => 500:"
109
+ log_system_error e
110
+ @msg.reply 500, "Internal Error", ["Content-Type: text/plain"], "#{e.class}: #{e.message}"
111
+ end
112
+ end.resume
113
+ end
114
+ end
115
+ private :process_request
116
+
117
+
118
+ # Process a received response.
119
+ def process_response
120
+ case @msg.sip_method
121
+ when :INVITE
122
+ if client_transaction = @msg.connection.class.invite_client_transactions[@msg.via_branch_id]
123
+ client_transaction.receive_response(@msg)
124
+ return
125
+ end
126
+ when :ACK
127
+ when :CANCEL
128
+ if client_transaction = @msg.connection.class.invite_client_transactions[@msg.via_branch_id]
129
+ client_transaction.receive_response_to_cancel(@msg)
130
+ return
131
+ end
132
+ else
133
+ if client_transaction = @msg.connection.class.non_invite_client_transactions[@msg.via_branch_id]
134
+ client_transaction.receive_response(@msg)
135
+ return
136
+ end
137
+ end
138
+ log_system_debug "ignoring a response non matching a client transaction (#{@msg.sip_method} #{@msg.status_code})" if $oversip_debug
139
+ end
140
+ private :process_response
141
+
142
+
143
+ # Check transaction.
144
+ def check_transaction
145
+ case @msg.sip_method
146
+
147
+ when :INVITE
148
+ if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
149
+ # If the retranmission arrives via a different connection (for TCP/TLS/WS/WSS) then use
150
+ # the new one.
151
+ if @msg.connection == server_transaction.request.connection
152
+ log_system_debug "INVITE retransmission received" if $oversip_debug
153
+ else
154
+ log_system_debug "INVITE retransmission received via other connection, updating server transaction" if $oversip_debug
155
+ server_transaction.request.connection = @msg.connection
156
+ end
157
+ server_transaction.retransmit_last_response
158
+ return true
159
+ end
160
+
161
+ when :ACK
162
+ # If there is associated INVITE transaction (so it has been rejected)
163
+ # pass ACK to the transaction.
164
+ if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
165
+ server_transaction.receive_ack
166
+ return true
167
+ # Absorb ACK for statelessly generated final responses by us.
168
+ elsif ::OverSIP::SIP::Tags.check_totag_for_sl_reply(@msg.to_tag)
169
+ log_system_debug "absorving ACK for a stateless final response" if $oversip_debug
170
+ return true
171
+ else
172
+ log_system_debug "passing ACK to the core" if $oversip_debug
173
+ return false
174
+ end
175
+
176
+ when :CANCEL
177
+ if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
178
+ case state = server_transaction.state
179
+ when :proceeding
180
+ log_system_debug "CANCEL matches an INVITE server transaction in proceeding state => 200" if $oversip_debug
181
+ @msg.reply 200, "Cancelled"
182
+ server_transaction.receive_cancel(@msg)
183
+ else
184
+ log_system_debug "CANCEL matches an INVITE server transaction in #{state} state => 200" if $oversip_debug
185
+ @msg.reply 200, "Cancelled"
186
+ end
187
+ else
188
+ log_system_debug "CANCEL does not match an INVITE server transaction => 481" if $oversip_debug
189
+ @msg.reply 481
190
+ end
191
+ return true
192
+
193
+ else
194
+ if server_transaction = @msg.connection.class.non_invite_server_transactions[@msg.via_branch_id]
195
+ # If the retranmission arrives via a different connection (for TCP/TLS) then use
196
+ # the new one.
197
+ if @msg.connection == server_transaction.request.connection
198
+ log_system_debug "#{server_transaction.request.sip_method} retransmission received" if $oversip_debug
199
+ else
200
+ log_system_debug "#{server_transaction.request.sip_method} retransmission received via other connection, updating server transaction" if $oversip_debug
201
+ server_transaction.request.connection = @msg.connection
202
+ end
203
+ server_transaction.retransmit_last_response
204
+ return true
205
+ end
206
+
207
+ end
208
+ end # def check_transaction
209
+ private :check_transaction
210
+
211
+ end
212
+
213
+ end
@@ -0,0 +1,51 @@
1
+ module OverSIP::SIP
2
+
3
+ class NameAddr < OverSIP::SIP::Uri
4
+
5
+ attr_reader :display_name
6
+
7
+
8
+ def self.parse value
9
+ name_addr = ::OverSIP::SIP::MessageParser.parse_uri value, true
10
+ raise ::OverSIP::ParsingError, "invalid NameAddr #{value.inspect}" unless name_addr.is_a? (::OverSIP::SIP::NameAddr)
11
+ name_addr
12
+ end
13
+
14
+
15
+ def initialize display_name=nil, scheme=:sip, user=nil, host=nil, port=nil
16
+ @display_name = display_name
17
+ @scheme = scheme.to_sym
18
+ @user = user
19
+ @host = host
20
+ @host_type = ::OverSIP::Utils.ip_type(host) || :domain if host
21
+ @port = port
22
+
23
+ @name_addr_modified = true
24
+ @uri_modified = true
25
+ end
26
+
27
+ def display_name= value
28
+ @display_name = value
29
+ @name_addr_modified = true
30
+ end
31
+
32
+ def to_s
33
+ return @name_addr if @name_addr and not @name_addr_modified and not @uri_modified
34
+
35
+ @name_addr = ""
36
+ ( @name_addr << '"' << @display_name << '" ' ) if @display_name
37
+ @name_addr << "<" << uri << ">"
38
+
39
+ @name_addr_modified = false
40
+ @name_addr
41
+
42
+ end
43
+ alias :inspect :to_s
44
+
45
+ def modified?
46
+ @uri_modified or @name_addr_modified
47
+ end
48
+
49
+ end
50
+
51
+ end
@@ -0,0 +1,324 @@
1
+ module OverSIP::SIP
2
+
3
+ class Proxy < Client
4
+
5
+ # If a SIP response is given then this method may offer other features such as replying 199.
6
+ def drop_response response=nil
7
+ @drop_response = true
8
+
9
+ # RFC 6228 (199 response).
10
+ # http://tools.ietf.org/html/rfc6228#section-6
11
+ if response and response.status_code >= 300 and
12
+ @request.sip_method == :INVITE and
13
+ @request.supported and @request.supported.include?("199")
14
+
15
+ @request.send :reply_199, response
16
+ end
17
+ end
18
+
19
+
20
+ def route request, dst_host=nil, dst_port=nil, dst_transport=nil
21
+ unless (@request = request).is_a? ::OverSIP::SIP::Request
22
+ raise ::OverSIP::RuntimeError, "request must be a OverSIP::SIP::Request instance"
23
+ end
24
+
25
+ @log_id = "Proxy #{@conf[:name]} #{@request.via_branch_id}"
26
+
27
+ # Create the server transaction if it doesn't exist yet.
28
+ @server_transaction = @request.server_transaction or case @request.sip_method
29
+ # Here it can arrive an INVITE, ACK-for-2XX and any method but CANCEL.
30
+ when :INVITE
31
+ InviteServerTransaction.new @request
32
+ when :ACK
33
+ else
34
+ NonInviteServerTransaction.new @request
35
+ end
36
+ @request.server_transaction ||= @server_transaction
37
+
38
+ # Set this core layer to the server transaction.
39
+ @request.server_transaction.core = self if @request.server_transaction
40
+
41
+ # NOTE: Routing can be based on incoming request for an Outbound (RFC 5626) connection
42
+ # or based on normal RFC 3263 procedures.
43
+
44
+ # If it's an incoming Outbound connection get the associated connection (but if dst_host is
45
+ # set then don't honor the Outbound connection).
46
+
47
+ if @request.incoming_outbound_requested? and not dst_host
48
+ @client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @conf, @request.route_outbound_flow_token
49
+
50
+ if @client_transaction.connection
51
+ add_routing_headers
52
+ @client_transaction.send_request
53
+ else
54
+ unless @request.sip_method == :ACK
55
+ log_system_debug "flow failed" if $oversip_debug
56
+
57
+ run_on_error_cbs 430, "Flow Failed", :flow_failed
58
+ unless @drop_response
59
+ @request.reply 430, "Flow Failed"
60
+ else
61
+ @drop_response = false
62
+ end
63
+ else
64
+ log_system_debug "flow failed for received ACK" if $oversip_debug
65
+ end
66
+ end
67
+
68
+ return
69
+ end
70
+
71
+
72
+ # If it's not an incoming Outbound connection (or explicit destination is set),
73
+ # let's perform RFC 3263 procedures.
74
+
75
+ # Check the request destination.
76
+ # If a destination is given use it. If not route based on request headers.
77
+
78
+ # Force the destination.
79
+ if dst_host
80
+ dst_scheme = :sip
81
+ dst_host_type = ::OverSIP::Utils.ip_type(dst_host) || :domain
82
+
83
+ # Or use top Route header.
84
+ elsif @request.routes
85
+ top_route = @request.routes[0]
86
+ dst_scheme = top_route.scheme
87
+ dst_host = top_route.host
88
+ dst_host_type = top_route.host_type
89
+ dst_port = top_route.port
90
+ dst_transport = top_route.transport_param
91
+
92
+ # Or use the Request URI.
93
+ else
94
+ dst_scheme = @request.ruri.scheme
95
+ dst_host = @request.ruri.host
96
+ dst_host_type = @request.ruri.host_type
97
+ dst_port = @request.ruri.port
98
+ dst_transport = @request.ruri.transport_param
99
+ end
100
+
101
+ # If the destination uri_host is an IPv6 reference, convert it to real IPv6.
102
+ if dst_host_type == :ipv6_reference
103
+ dst_host = ::OverSIP::Utils.normalize_ipv6(dst_host, true)
104
+ dst_host_type = :ipv6
105
+ end
106
+
107
+ # Loockup in the DNS cache of this proxy.
108
+ result = check_dns_cache dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
109
+
110
+ case result
111
+ when true
112
+ return
113
+ else # It can be String or nil, so use it as dns_cache_key param.
114
+ # Perform RFC 3263 procedures.
115
+ do_dns result, @request.via_branch_id, dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
116
+ end
117
+
118
+ end # def route
119
+
120
+
121
+ def receive_response response
122
+ log_system_debug "received response #{response.status_code}" if $oversip_debug
123
+
124
+ response.delete_header_top "Via"
125
+
126
+ if @request.server_transaction.valid_response? response.status_code
127
+ if response.status_code < 200 && ! @canceled
128
+ run_on_provisional_response_cbs response
129
+ elsif response.status_code >= 200 && response.status_code <= 299
130
+ run_on_success_response_cbs response
131
+ elsif response.status_code >= 300 && ! @canceled
132
+ if response.status_code == 503
133
+ if @conf[:dns_failover_on_503]
134
+ try_next_target nil, nil, response
135
+ return
136
+ else
137
+ # If the response is 503 convert it into 500 (RFC 3261 16.7).
138
+ response.status_code = 500
139
+ run_on_failure_response_cbs response
140
+ end
141
+ else
142
+ run_on_failure_response_cbs response
143
+ end
144
+ end
145
+ end
146
+
147
+ unless @drop_response
148
+ @request.reply_full response
149
+ else
150
+ @drop_response = false
151
+ end
152
+ end
153
+
154
+
155
+ # Since we don't implement parallel forking, directly send our CANCEL downstream.
156
+ def receive_cancel cancel
157
+ log_system_debug "server transaction canceled, cancelling pending client transaction" if $oversip_debug
158
+
159
+ @canceled = true
160
+ run_on_canceled_cbs
161
+
162
+ @client_transaction.do_cancel cancel
163
+ end
164
+
165
+
166
+ # Timer C for INVITE (method called by the client transaction).
167
+ def invite_timeout
168
+ run_on_invite_timeout_cbs
169
+
170
+ unless @drop_response
171
+ @request.reply 408, "INVITE Timeout"
172
+ end
173
+ @drop_response = true # Ignore the possible 487 got from the callee.
174
+ end
175
+
176
+
177
+
178
+ private
179
+
180
+
181
+ def add_routing_headers
182
+ # Don't add routing headers again if we are in DNS failover within the same Proxy instance.
183
+ # But we must run this method if it's an incoming request asking for Outbound usage (in this
184
+ # case @num_target is nil so the method continues).
185
+ return if @num_target and @num_target > 1
186
+
187
+ add_rr_path = false
188
+
189
+ # NOTE: As per RFC 6665 the proxy MUST add Record-Route to in-dialog NOTIFY's.
190
+ if (@request.initial? and @request.record_routing_aware?) or @request.sip_method == :NOTIFY or @conf[:record_route_all]
191
+ do_record_routing = @conf[:do_record_routing]
192
+
193
+ # Request has no previous RR/Path and current proxy performs record-routing.
194
+ # So add RR/Path.
195
+ if ! @request.in_rr && do_record_routing
196
+ add_rr_path = true
197
+
198
+ # Request has previous RR/Path and current proxy does not perform record-routing.
199
+ # So don't add RR/Path and remove the existing one.
200
+ elsif @request.in_rr && ! do_record_routing
201
+ case @request.in_rr
202
+ when :rr, :outgoing_outbound_rr, :incoming_outbound_rr, :both_outbound_rr
203
+ @request.delete_header_top "Record-Route"
204
+ when :path, :outgoing_outbound_path, :incoming_outbound_path, :both_outbound_path
205
+ @request.delete_header_top "Path"
206
+ end
207
+ @request.in_rr = nil
208
+
209
+ # Remaining cases are:
210
+ # - Request has previous RR/Path and current proxy performs record-routing.
211
+ # - Request has no previous RR/Path and current proxy does not perform record-routing.
212
+ # So don't add RR/Path.
213
+ end
214
+ end
215
+
216
+ unless @request.proxied
217
+ # Indicate that this request has been proxied (at least once).
218
+ @request.proxied = true
219
+
220
+ # Set the Max-Forwards header.
221
+ @request.headers["Max-Forwards"] = [ @request.new_max_forwards.to_s ] if @request.new_max_forwards
222
+ end
223
+
224
+ # Add Record-Route or Path header.
225
+ if add_rr_path
226
+ case @request.sip_method
227
+
228
+ # Path header (RFC 3327) for REGISTER.
229
+ when :REGISTER
230
+ if @request.outgoing_outbound_requested?
231
+ if @request.incoming_outbound_requested?
232
+ @request.in_rr = :both_outbound_path
233
+ else
234
+ @request.in_rr = :outgoing_outbound_path
235
+ end
236
+ @request.insert_header "Path", "<sip:" << @request.connection_outbound_flow_token << @request.connection.class.outbound_path_fragment
237
+ elsif @request.incoming_outbound_requested?
238
+ @request.in_rr = :incoming_outbound_path
239
+ @request.insert_header "Path", @request.connection.class.record_route
240
+ else
241
+ @request.in_rr = :path
242
+ # The request comes via UDP or via a connection made by the client.
243
+ if @request.connection.class.outbound_listener?
244
+ @request.insert_header "Path", @request.connection.class.record_route
245
+ # The request comes via a TCP/TLS connection made by OverSIP.
246
+ else
247
+ @request.insert_header "Path", @request.connection.record_route
248
+ end
249
+ end
250
+
251
+ # Record-Route for INVITE, SUBSCRIBE, REFER and in-dialog NOTIFY.
252
+ else
253
+ if @request.outgoing_outbound_requested?
254
+ if @request.incoming_outbound_requested?
255
+ @request.in_rr = :both_outbound_rr
256
+ else
257
+ @request.in_rr = :outgoing_outbound_rr
258
+ end
259
+ @request.insert_header "Record-Route", "<sip:" << @request.connection_outbound_flow_token << @request.connection.class.outbound_record_route_fragment
260
+ elsif @request.incoming_outbound_requested?
261
+ @request.in_rr = :incoming_outbound_rr
262
+ # The request comes via UDP or via a connection made by the client.
263
+ if @request.connection.class.outbound_listener?
264
+ @request.insert_header "Record-Route", @request.connection.class.record_route
265
+ # The request comes via a TCP/TLS connection made by OverSIP.
266
+ else
267
+ @request.insert_header "Record-Route", @request.connection.record_route
268
+ end
269
+ else
270
+ @request.in_rr = :rr
271
+ # The request comes via UDP or via a connection made by the client.
272
+ if @request.connection.class.outbound_listener?
273
+ @request.insert_header "Record-Route", "<sip:" << @request.connection_outbound_flow_token << @request.connection.class.outbound_record_route_fragment
274
+ # The request comes via a TCP/TLS connection made by OverSIP.
275
+ else
276
+ @request.insert_header "Record-Route", @request.connection.record_route
277
+ end
278
+ end
279
+
280
+ end
281
+ end
282
+
283
+ end # add_routing_headers
284
+
285
+
286
+ def no_more_targets status, reason, full_response, code
287
+ # If we have received a [3456]XX response from downstream then run @on_failure_response_cbs.
288
+ if full_response
289
+ run_on_failure_response_cbs full_response
290
+ unless @drop_response
291
+ # If the response is 503 convert it into 500 (RFC 3261 16.7).
292
+ full_response.status_code = 500 if full_response.status_code == 503
293
+ @request.reply_full full_response
294
+ else
295
+ @drop_response = false
296
+ end
297
+
298
+ # If not, generate the response according to the given status and reason.
299
+ else
300
+ run_on_error_cbs status, reason, code
301
+ unless @drop_response
302
+ @request.reply status, reason
303
+ else
304
+ @drop_response = false
305
+ end
306
+
307
+ end
308
+ end # no_more_targets
309
+
310
+
311
+ def do_dns_fail status, reason, code
312
+ run_on_error_cbs status, reason, code
313
+
314
+ unless @drop_response
315
+ @request.reply status, reason unless @request.sip_method == :ACK
316
+ else
317
+ @drop_response = false
318
+ end
319
+ end
320
+
321
+
322
+ end # class Proxy
323
+
324
+ end