oversip 0.9.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.
- data/AUTHORS.txt +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +55 -0
- data/bin/oversip +182 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +209 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_parser.c +29649 -0
- data/ext/sip_parser/sip_parser.h +227 -0
- data/ext/sip_parser/sip_parser_ruby.c +1292 -0
- data/ext/stud/extconf.rb +27 -0
- data/ext/stud/stud.tar.gz +0 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +391 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +61 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +384 -0
- data/ext/utils/utils_ruby.h +75 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
- data/ext/websocket_http_parser/ws_http_parser.h +86 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +541 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/errors.rb +7 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +507 -0
- data/lib/oversip/logger.rb +170 -0
- data/lib/oversip/master_process.rb +67 -0
- data/lib/oversip/posix_mq.rb +121 -0
- data/lib/oversip/proxies_config.rb +169 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client_transaction.rb +587 -0
- data/lib/oversip/sip/constants.rb +87 -0
- data/lib/oversip/sip/grammar/name_addr.rb +27 -0
- data/lib/oversip/sip/grammar/uri.rb +116 -0
- data/lib/oversip/sip/launcher.rb +180 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/reactor.rb +39 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
- data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +117 -0
- data/lib/oversip/sip/listeners/tls_server.rb +70 -0
- data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
- data/lib/oversip/sip/listeners.rb +28 -0
- data/lib/oversip/sip/logic.rb +14 -0
- data/lib/oversip/sip/message.rb +168 -0
- data/lib/oversip/sip/message_processor.rb +202 -0
- data/lib/oversip/sip/modules/core.rb +200 -0
- data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
- data/lib/oversip/sip/modules/user_assertion.rb +123 -0
- data/lib/oversip/sip/proxy.rb +460 -0
- data/lib/oversip/sip/request.rb +128 -0
- data/lib/oversip/sip/response.rb +30 -0
- data/lib/oversip/sip/rfc3263.rb +646 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +74 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +129 -0
- data/lib/oversip/syslogger_process.rb +119 -0
- data/lib/oversip/tls.rb +179 -0
- data/lib/oversip/utils.rb +25 -0
- data/lib/oversip/version.rb +23 -0
- data/lib/oversip/websocket/constants.rb +56 -0
- data/lib/oversip/websocket/default_policy.rb +19 -0
- data/lib/oversip/websocket/http_request.rb +63 -0
- data/lib/oversip/websocket/launcher.rb +207 -0
- data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
- data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
- data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
- data/lib/oversip/websocket/listeners.rb +12 -0
- data/lib/oversip/websocket/ws_app.rb +75 -0
- data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
- data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
- data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
- data/lib/oversip/websocket/ws_apps.rb +9 -0
- data/lib/oversip/websocket/ws_framing.rb +597 -0
- data/lib/oversip.rb +59 -0
- data/test/oversip_test_helper.rb +20 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_sip_parser.rb +139 -0
- metadata +256 -0
|
@@ -0,0 +1,460 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class Proxy
|
|
4
|
+
|
|
5
|
+
include ::OverSIP::Logger
|
|
6
|
+
|
|
7
|
+
def initialize request, proxy_conf
|
|
8
|
+
@request = request
|
|
9
|
+
@proxy_conf = proxy_conf
|
|
10
|
+
@log_id = "Proxy #{proxy_conf[:name]} #{request.via_branch_id}"
|
|
11
|
+
|
|
12
|
+
# Create the server transaction if it doesn't exist yet.
|
|
13
|
+
@server_transaction = @request.server_transaction or case @request.sip_method
|
|
14
|
+
# Here it can arrive an INVITE, ACK-for-2XX and any method but CANCEL.
|
|
15
|
+
when :INVITE
|
|
16
|
+
InviteServerTransaction.new @request
|
|
17
|
+
when :ACK
|
|
18
|
+
else
|
|
19
|
+
NonInviteServerTransaction.new @request
|
|
20
|
+
end
|
|
21
|
+
@request.server_transaction ||= @server_transaction
|
|
22
|
+
|
|
23
|
+
# Set this core layer to the server transaction.
|
|
24
|
+
@request.server_transaction.core = self if @request.server_transaction
|
|
25
|
+
end # initialize
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
def on_provisional_response &block
|
|
29
|
+
@on_provisional_response_block = block
|
|
30
|
+
end
|
|
31
|
+
|
|
32
|
+
def on_success_response &block
|
|
33
|
+
@on_success_response_block = block
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
def on_failure_response &block
|
|
37
|
+
@on_failure_response_block = block
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
def on_canceled &block
|
|
41
|
+
@on_canceled_block = block
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
def on_invite_timeout &block
|
|
45
|
+
@on_invite_timeout_block = block
|
|
46
|
+
end
|
|
47
|
+
|
|
48
|
+
def on_error &block
|
|
49
|
+
@on_error_block = block
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
# If called, current response within the called callback won't be forwarded.
|
|
53
|
+
def drop_response
|
|
54
|
+
@drop_response = true
|
|
55
|
+
end
|
|
56
|
+
|
|
57
|
+
|
|
58
|
+
def route dst_host=nil, dst_port=nil, dst_transport=nil
|
|
59
|
+
# NOTE: Routing can be based on incoming request for an Outbound (RFC 5626) connection
|
|
60
|
+
# or based on normal RFC 3263 procedures.
|
|
61
|
+
|
|
62
|
+
# If it's an incoming Outbound connection get the associated connection (but if dst_host is
|
|
63
|
+
# set then don't honor the Outbound connection).
|
|
64
|
+
|
|
65
|
+
if @request.incoming_outbound_requested? and not dst_host
|
|
66
|
+
@client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @proxy_conf, @request.route_outbound_flow_token
|
|
67
|
+
|
|
68
|
+
if @client_transaction.connection
|
|
69
|
+
add_routing_headers
|
|
70
|
+
@client_transaction.send_request
|
|
71
|
+
else
|
|
72
|
+
unless @request.sip_method == :ACK
|
|
73
|
+
log_system_debug "flow failed" if $oversip_debug
|
|
74
|
+
|
|
75
|
+
@on_error_block && @on_error_block.call(430, "Flow Failed")
|
|
76
|
+
unless @drop_response
|
|
77
|
+
@request.reply 430, "Flow Failed"
|
|
78
|
+
else
|
|
79
|
+
@drop_response = false
|
|
80
|
+
end
|
|
81
|
+
else
|
|
82
|
+
log_system_debug "flow failed for received ACK" if $oversip_debug
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
return
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
|
|
90
|
+
# If it's not an incoming Outbound connection (or explicit destination is set),
|
|
91
|
+
# let's perform RFC 3263 procedures.
|
|
92
|
+
|
|
93
|
+
# Check the request destination.
|
|
94
|
+
# If a destination is given use it. If not route based on request headers.
|
|
95
|
+
|
|
96
|
+
# Force the destination.
|
|
97
|
+
if dst_host
|
|
98
|
+
dst_scheme = :sip
|
|
99
|
+
dst_host_type = ::OverSIP::Utils.ip_type(dst_host) || :domain
|
|
100
|
+
|
|
101
|
+
# Or use top Route header.
|
|
102
|
+
elsif @request.routes
|
|
103
|
+
top_route = @request.routes[0]
|
|
104
|
+
dst_scheme = top_route.scheme
|
|
105
|
+
dst_host = top_route.host
|
|
106
|
+
dst_host_type = top_route.host_type
|
|
107
|
+
dst_port = top_route.port
|
|
108
|
+
dst_transport = top_route.transport_param
|
|
109
|
+
|
|
110
|
+
# Or use the Request URI.
|
|
111
|
+
else
|
|
112
|
+
dst_scheme = @request.ruri.scheme
|
|
113
|
+
dst_host = @request.ruri.host
|
|
114
|
+
dst_host_type = @request.ruri.host_type
|
|
115
|
+
dst_port = @request.ruri.port
|
|
116
|
+
dst_transport = @request.ruri.transport_param
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# If the destination uri_host is an IPv6 reference, convert it to real IPv6.
|
|
120
|
+
if dst_host_type == :ipv6_reference
|
|
121
|
+
dst_host = ::OverSIP::Utils.normalize_ipv6(dst_host, true)
|
|
122
|
+
dst_host_type = :ipv6
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Loockup in the DNS cache of this proxy.
|
|
126
|
+
if dst_host_type == :domain and @proxy_conf[:use_dns_cache]
|
|
127
|
+
dns_cache_entry = "#{dst_host}|#{dst_port}|#{dst_transport}|#{dst_scheme}"
|
|
128
|
+
if (result = @proxy_conf[:dns_cache][dns_cache_entry])
|
|
129
|
+
log_system_debug "destination found in the DNS cache" if $oversip_debug
|
|
130
|
+
if result.is_a? ::Symbol
|
|
131
|
+
rfc3263_failed result
|
|
132
|
+
else
|
|
133
|
+
rfc3263_succeeded result
|
|
134
|
+
end
|
|
135
|
+
return
|
|
136
|
+
end
|
|
137
|
+
else
|
|
138
|
+
dns_cache_entry = nil
|
|
139
|
+
end
|
|
140
|
+
|
|
141
|
+
# Perform RFC 3261 procedures.
|
|
142
|
+
dns_query = ::OverSIP::SIP::RFC3263::Query.new @proxy_conf, @request.via_branch_id, dst_scheme, dst_host, dst_host_type, dst_port, dst_transport
|
|
143
|
+
case result = dns_query.resolve
|
|
144
|
+
|
|
145
|
+
# Async result so DNS took place.
|
|
146
|
+
when nil
|
|
147
|
+
# Async success.
|
|
148
|
+
dns_query.callback do |result|
|
|
149
|
+
# Store the result in the DNS cache.
|
|
150
|
+
if dns_cache_entry
|
|
151
|
+
@proxy_conf[:dns_cache][dns_cache_entry] = result
|
|
152
|
+
::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
|
|
153
|
+
end
|
|
154
|
+
rfc3263_succeeded result
|
|
155
|
+
end
|
|
156
|
+
# Async error.
|
|
157
|
+
dns_query.errback do |result|
|
|
158
|
+
# Store the result in the DNS cache.
|
|
159
|
+
if dns_cache_entry
|
|
160
|
+
@proxy_conf[:dns_cache][dns_cache_entry] = result
|
|
161
|
+
::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
|
|
162
|
+
end
|
|
163
|
+
rfc3263_failed result
|
|
164
|
+
end
|
|
165
|
+
# Instant error.
|
|
166
|
+
when ::Symbol
|
|
167
|
+
# Store the result in the DNS cache.
|
|
168
|
+
if dns_cache_entry
|
|
169
|
+
@proxy_conf[:dns_cache][dns_cache_entry] = result
|
|
170
|
+
::EM.add_timer(@proxy_conf[:dns_cache_time]) { @proxy_conf[:dns_cache].delete dns_cache_entry }
|
|
171
|
+
end
|
|
172
|
+
rfc3263_failed result
|
|
173
|
+
# Instant success so it's not a domain (no DNS performed).
|
|
174
|
+
else
|
|
175
|
+
rfc3263_succeeded result
|
|
176
|
+
end
|
|
177
|
+
|
|
178
|
+
end # def route
|
|
179
|
+
|
|
180
|
+
|
|
181
|
+
def receive_response response
|
|
182
|
+
log_system_debug "received response #{response.status_code}"
|
|
183
|
+
|
|
184
|
+
response.delete_header_top "Via"
|
|
185
|
+
|
|
186
|
+
if @request.server_transaction.valid_response? response.status_code
|
|
187
|
+
if response.status_code < 200 && ! @canceled
|
|
188
|
+
@on_provisional_response_block && @on_provisional_response_block.call(response)
|
|
189
|
+
elsif response.status_code >= 200 && response.status_code <= 299
|
|
190
|
+
@on_success_response_block && @on_success_response_block.call(response)
|
|
191
|
+
elsif response.status_code >= 300 && ! @canceled
|
|
192
|
+
if response.status_code == 503
|
|
193
|
+
if @proxy_conf[:dns_failover_on_503]
|
|
194
|
+
try_next_target nil, nil, response
|
|
195
|
+
return
|
|
196
|
+
else
|
|
197
|
+
# If the response is 503 convert it into 500 (RFC 3261 16.7).
|
|
198
|
+
response.status_code = 500
|
|
199
|
+
@on_failure_response_block && @on_failure_response_block.call(response)
|
|
200
|
+
end
|
|
201
|
+
else
|
|
202
|
+
@on_failure_response_block && @on_failure_response_block.call(response)
|
|
203
|
+
end
|
|
204
|
+
end
|
|
205
|
+
end
|
|
206
|
+
|
|
207
|
+
unless @drop_response
|
|
208
|
+
@request.reply_full response
|
|
209
|
+
else
|
|
210
|
+
@drop_response = false
|
|
211
|
+
end
|
|
212
|
+
end
|
|
213
|
+
|
|
214
|
+
|
|
215
|
+
# Since we don't implement parallel forking, directly send our CANCEL downstream.
|
|
216
|
+
def receive_cancel cancel
|
|
217
|
+
log_system_debug "server transaction canceled, cancelling pending client transaction" if $oversip_debug
|
|
218
|
+
|
|
219
|
+
@canceled = true
|
|
220
|
+
@on_canceled_block && @on_canceled_block.call
|
|
221
|
+
|
|
222
|
+
@client_transaction.do_cancel cancel
|
|
223
|
+
end
|
|
224
|
+
|
|
225
|
+
|
|
226
|
+
def client_timeout
|
|
227
|
+
try_next_target 408, "Client Timeout"
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
|
|
231
|
+
def connection_failed
|
|
232
|
+
try_next_target 500, "Connection Error"
|
|
233
|
+
end
|
|
234
|
+
|
|
235
|
+
|
|
236
|
+
def tls_validation_failed
|
|
237
|
+
try_next_target 500, "TLS Validation Failed"
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
|
|
241
|
+
# Timer C for INVITE.
|
|
242
|
+
def invite_timeout
|
|
243
|
+
@on_invite_timeout_block && @on_invite_timeout_block.call
|
|
244
|
+
|
|
245
|
+
unless @drop_response
|
|
246
|
+
@request.reply 408, "INVITE Timeout"
|
|
247
|
+
end
|
|
248
|
+
@drop_response = true # Ignore the possible 487 got from the callee.
|
|
249
|
+
end
|
|
250
|
+
|
|
251
|
+
|
|
252
|
+
private
|
|
253
|
+
|
|
254
|
+
|
|
255
|
+
def add_routing_headers
|
|
256
|
+
# Don't add routing headers again if we are in DNS failover within the same Proxy instance.
|
|
257
|
+
# But we must run this method if it's an incoming request asking for Outbound usage (in this
|
|
258
|
+
# case @num_target is nil so the method continues).
|
|
259
|
+
return if @num_target and @num_target > 0
|
|
260
|
+
|
|
261
|
+
add_rr_path = false
|
|
262
|
+
if @request.initial? && @request.loose_record_aware?
|
|
263
|
+
do_loose_routing = @proxy_conf[:do_loose_routing]
|
|
264
|
+
|
|
265
|
+
# Request has no previous RR/Path and current proxy performs loose-routing.
|
|
266
|
+
# So add RR/Path.
|
|
267
|
+
if ! @request.in_rr && do_loose_routing
|
|
268
|
+
add_rr_path = true
|
|
269
|
+
|
|
270
|
+
# Request has previous RR/Path and current proxy does not perform loose-routing.
|
|
271
|
+
# So don't add RR/Path and remove the existing one.
|
|
272
|
+
elsif @request.in_rr && ! do_loose_routing
|
|
273
|
+
case @request.in_rr
|
|
274
|
+
when :rr, :outgoing_outbound_rr, :incoming_outbound_rr, :both_outbound_rr
|
|
275
|
+
@request.delete_header_top "Record-Route"
|
|
276
|
+
when :path, :outgoing_outbound_path, :incoming_outbound_path, :both_outbound_path
|
|
277
|
+
@request.delete_header_top "Path"
|
|
278
|
+
end
|
|
279
|
+
@request.in_rr = nil
|
|
280
|
+
|
|
281
|
+
# Remaining cases are:
|
|
282
|
+
# - Request has previous RR/Path and current proxy performs loose-routing.
|
|
283
|
+
# - Request has no previous RR/Path and current proxy does not perform loose-routing.
|
|
284
|
+
# So don't add RR/Path.
|
|
285
|
+
end
|
|
286
|
+
end
|
|
287
|
+
|
|
288
|
+
unless @request.proxied
|
|
289
|
+
# Indicate that this request has been proxied (at least once).
|
|
290
|
+
@request.proxied = true
|
|
291
|
+
|
|
292
|
+
# Set the Max-Forwards header.
|
|
293
|
+
@request.headers["Max-Forwards"] = [ @request.new_max_forwards.to_s ] if @request.new_max_forwards
|
|
294
|
+
end
|
|
295
|
+
|
|
296
|
+
# Add Record-Route or Path header.
|
|
297
|
+
# Here we only arrive if @request.loose_record_aware?, so method is INVITE, REGISTER, SUBSCRIBE or REFER.
|
|
298
|
+
if add_rr_path
|
|
299
|
+
case @request.sip_method
|
|
300
|
+
|
|
301
|
+
# Path header (RFC 3327) for REGISTER.
|
|
302
|
+
when :REGISTER
|
|
303
|
+
if @request.outgoing_outbound_requested?
|
|
304
|
+
if @request.incoming_outbound_requested?
|
|
305
|
+
@request.in_rr = :both_outbound_path
|
|
306
|
+
else
|
|
307
|
+
@request.in_rr = :outgoing_outbound_path
|
|
308
|
+
end
|
|
309
|
+
@request.insert_header "Path", "<sip:" << @request.connection_outbound_flow_token << @request.connection.class.outbound_path_fragment
|
|
310
|
+
elsif @request.incoming_outbound_requested?
|
|
311
|
+
@request.in_rr = :incoming_outbound_path
|
|
312
|
+
@request.insert_header "Path", @request.connection.class.record_route
|
|
313
|
+
else
|
|
314
|
+
@request.in_rr = :path
|
|
315
|
+
@request.insert_header "Path", @request.connection.class.record_route
|
|
316
|
+
end
|
|
317
|
+
|
|
318
|
+
# Record-Route for INVITE, SUBSCRIBE, REFER.
|
|
319
|
+
else
|
|
320
|
+
if @request.outgoing_outbound_requested?
|
|
321
|
+
if @request.incoming_outbound_requested?
|
|
322
|
+
@request.in_rr = :both_outbound_rr
|
|
323
|
+
else
|
|
324
|
+
@request.in_rr = :outgoing_outbound_rr
|
|
325
|
+
end
|
|
326
|
+
@request.insert_header "Record-Route", "<sip:" << @request.connection_outbound_flow_token << @request.connection.class.outbound_record_route_fragment
|
|
327
|
+
elsif @request.incoming_outbound_requested?
|
|
328
|
+
@request.in_rr = :incoming_outbound_rr
|
|
329
|
+
@request.insert_header "Record-Route", @request.connection.class.record_route
|
|
330
|
+
else
|
|
331
|
+
@request.in_rr = :rr
|
|
332
|
+
@request.insert_header "Record-Route", @request.connection.class.record_route
|
|
333
|
+
end
|
|
334
|
+
|
|
335
|
+
end
|
|
336
|
+
end
|
|
337
|
+
|
|
338
|
+
end # add_routing_headers
|
|
339
|
+
|
|
340
|
+
|
|
341
|
+
def rfc3263_succeeded result
|
|
342
|
+
#log_system_debug "RFC3263 result: #{result.class}: #{result.inspect}" if $oversip_debug
|
|
343
|
+
|
|
344
|
+
# After RFC 3263 (DNS) resolution we get N targets.
|
|
345
|
+
@num_target = 0 # First target is 0 (rather than 1).
|
|
346
|
+
|
|
347
|
+
case result
|
|
348
|
+
|
|
349
|
+
when RFC3263::Target
|
|
350
|
+
@target = result # Single Target.
|
|
351
|
+
|
|
352
|
+
when RFC3263::SrvTargets
|
|
353
|
+
log_system_debug "result is srv targets => randomizing:" if $oversip_debug
|
|
354
|
+
@targets = result.randomize # Array of Targets.
|
|
355
|
+
|
|
356
|
+
# This can contain Target and SrvTargets entries.
|
|
357
|
+
when RFC3263::MultiTargets
|
|
358
|
+
log_system_debug "result is MultiTargets => flatting:" if $oversip_debug
|
|
359
|
+
@targets = result.flatten # Array of Targets.
|
|
360
|
+
|
|
361
|
+
# NOTE: Should never happen.
|
|
362
|
+
else
|
|
363
|
+
raise "rfc3263_succeeded returns a #{result.class}: #{result.inspect}"
|
|
364
|
+
|
|
365
|
+
end
|
|
366
|
+
|
|
367
|
+
try_next_target
|
|
368
|
+
end # rfc3263_succeeded
|
|
369
|
+
|
|
370
|
+
|
|
371
|
+
def try_next_target status=nil, reason=nil, full_response=nil
|
|
372
|
+
# Single target.
|
|
373
|
+
if @target and @num_target == 0
|
|
374
|
+
log_system_debug "using single target: #{@target}" if $oversip_debug
|
|
375
|
+
use_target @target
|
|
376
|
+
@num_target = 1
|
|
377
|
+
|
|
378
|
+
# Multiple targets (so @targets is set).
|
|
379
|
+
elsif @targets and @num_target < @targets.size
|
|
380
|
+
log_system_debug "using target #{@num_target+1} of #{@targets.size}: #{@targets[@num_target]}" if $oversip_debug
|
|
381
|
+
use_target @targets[@num_target]
|
|
382
|
+
@num_target += 1
|
|
383
|
+
|
|
384
|
+
# No more targets.
|
|
385
|
+
else
|
|
386
|
+
# If we have received a [3456]XX response from downstream then run @on_failure_block.
|
|
387
|
+
if full_response
|
|
388
|
+
@on_failure_response_block && @on_failure_response_block.call(full_response)
|
|
389
|
+
unless @drop_response
|
|
390
|
+
# If the response is 503 convert it into 500 (RFC 3261 16.7).
|
|
391
|
+
full_response.status_code = 500 if full_response.status_code == 503
|
|
392
|
+
@request.reply_full full_response
|
|
393
|
+
else
|
|
394
|
+
@drop_response = false
|
|
395
|
+
end
|
|
396
|
+
|
|
397
|
+
# If not, generate the response according to the given status and reason.
|
|
398
|
+
else
|
|
399
|
+
@on_error_block && @on_error_block.call(status, reason)
|
|
400
|
+
unless @drop_response
|
|
401
|
+
@request.reply status, reason
|
|
402
|
+
else
|
|
403
|
+
@drop_response = false
|
|
404
|
+
end
|
|
405
|
+
|
|
406
|
+
end
|
|
407
|
+
end
|
|
408
|
+
end # try_next_target
|
|
409
|
+
|
|
410
|
+
|
|
411
|
+
def use_target target
|
|
412
|
+
@client_transaction = (::OverSIP::SIP::ClientTransaction.get_class @request).new self, @request, @proxy_conf, target.transport, target.ip, target.ip_type, target.port
|
|
413
|
+
add_routing_headers
|
|
414
|
+
@client_transaction.send_request
|
|
415
|
+
end
|
|
416
|
+
|
|
417
|
+
|
|
418
|
+
def rfc3263_failed error
|
|
419
|
+
case error
|
|
420
|
+
when :rfc3263_domain_not_found
|
|
421
|
+
log_system_debug "no resolution" if $oversip_debug
|
|
422
|
+
status = 404
|
|
423
|
+
reason = "No DNS Resolution"
|
|
424
|
+
when :rfc3263_unsupported_scheme
|
|
425
|
+
log_system_debug "unsupported URI scheme" if $oversip_debug
|
|
426
|
+
status = 416
|
|
427
|
+
reason = "Unsupported URI scheme"
|
|
428
|
+
when :rfc3263_unsupported_transport
|
|
429
|
+
log_system_debug "unsupported transport" if $oversip_debug
|
|
430
|
+
status = 478
|
|
431
|
+
reason = "Unsupported Transport"
|
|
432
|
+
when :rfc3263_wrong_transport
|
|
433
|
+
log_system_debug "wrong URI transport" if $oversip_debug
|
|
434
|
+
status = 478
|
|
435
|
+
reason = "Wrong URI Transport"
|
|
436
|
+
when :rfc3263_no_ipv4
|
|
437
|
+
log_system_debug "destination requires unsupported IPv4" if $oversip_debug
|
|
438
|
+
status = 478
|
|
439
|
+
reason = "Destination Requires Unsupported IPv4"
|
|
440
|
+
when :rfc3263_no_ipv6
|
|
441
|
+
log_system_debug "destination requires unsupported IPv6" if $oversip_debug
|
|
442
|
+
status = 478
|
|
443
|
+
reason = "Destination Requires Unsupported IPv6"
|
|
444
|
+
when :rfc3263_no_dns
|
|
445
|
+
log_system_debug "destination requires unsupported DNS query" if $oversip_debug
|
|
446
|
+
status = 478
|
|
447
|
+
reason = "Destination Requires Unsupported DNS Query"
|
|
448
|
+
end
|
|
449
|
+
|
|
450
|
+
@on_error_block && @on_error_block.call(status, reason)
|
|
451
|
+
unless @drop_response
|
|
452
|
+
@request.reply status, reason unless @request.sip_method == :ACK
|
|
453
|
+
else
|
|
454
|
+
@drop_response = false
|
|
455
|
+
end
|
|
456
|
+
end # def rfc3263_failed
|
|
457
|
+
|
|
458
|
+
end # class Proxy
|
|
459
|
+
|
|
460
|
+
end
|
|
@@ -0,0 +1,128 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class Request < Message
|
|
4
|
+
|
|
5
|
+
SECURE_TRANSPORTS = { :tls=>true, :wss=>true }
|
|
6
|
+
|
|
7
|
+
attr_accessor :server_transaction
|
|
8
|
+
attr_reader :ruri
|
|
9
|
+
attr_reader :new_max_forwards
|
|
10
|
+
attr_accessor :antiloop_id
|
|
11
|
+
attr_accessor :route_outbound_flow_token
|
|
12
|
+
|
|
13
|
+
attr_writer :outgoing_outbound_requested, :incoming_outbound_requested
|
|
14
|
+
attr_accessor :proxied # If true it means that this request has been already proxied.
|
|
15
|
+
|
|
16
|
+
# Used for internal purposes when doing proxy and adding the first Record-Route
|
|
17
|
+
# or Path.
|
|
18
|
+
attr_accessor :in_rr
|
|
19
|
+
|
|
20
|
+
|
|
21
|
+
def log_id
|
|
22
|
+
@log_id ||= "SIP Request #{@via_branch_id}"
|
|
23
|
+
end
|
|
24
|
+
|
|
25
|
+
def request? ; true end
|
|
26
|
+
def response? ; false end
|
|
27
|
+
|
|
28
|
+
def initial? ; ! @to_tag end
|
|
29
|
+
def in_dialog? ; @to_tag end
|
|
30
|
+
|
|
31
|
+
def secure?
|
|
32
|
+
SECURE_TRANSPORTS[@transport] || false
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def reply status_code, reason_phrase=nil, extra_headers=[], body=nil
|
|
37
|
+
return false unless @server_transaction.receive_response(status_code) if @server_transaction
|
|
38
|
+
|
|
39
|
+
reason_phrase ||= REASON_PHARSE[status_code] || REASON_PHARSE_NOT_SET
|
|
40
|
+
|
|
41
|
+
if status_code > 100
|
|
42
|
+
@internal_to_tag ||= @to_tag || ( @server_transaction ? SecureRandom.hex(6) : OverSIP::SIP::Tags.totag_for_sl_reply )
|
|
43
|
+
end
|
|
44
|
+
|
|
45
|
+
response = "SIP/2.0 #{status_code} #{reason_phrase}\r\n"
|
|
46
|
+
|
|
47
|
+
@hdr_via.each do |hdr|
|
|
48
|
+
response << "Via: " << hdr << "\r\n"
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
response << "From: " << @hdr_from << "\r\n"
|
|
52
|
+
|
|
53
|
+
response << "To: " << @hdr_to
|
|
54
|
+
response << ";tag=#{@internal_to_tag}" if @internal_to_tag
|
|
55
|
+
response << "\r\n"
|
|
56
|
+
|
|
57
|
+
response << "Call-ID: " << @call_id << "\r\n"
|
|
58
|
+
response << "CSeq: " << @cseq.to_s << " " << @sip_method.to_s << "\r\n"
|
|
59
|
+
response << "Content-Length: #{body ? body.bytesize : "0"}\r\n"
|
|
60
|
+
|
|
61
|
+
extra_headers.each do |header|
|
|
62
|
+
response << header.to_s << "\r\n"
|
|
63
|
+
end if extra_headers
|
|
64
|
+
|
|
65
|
+
response << HDR_SERVER << "\r\n"
|
|
66
|
+
response << "\r\n"
|
|
67
|
+
|
|
68
|
+
response << body if body
|
|
69
|
+
|
|
70
|
+
@server_transaction.last_response = response if @server_transaction
|
|
71
|
+
|
|
72
|
+
log_system_debug "replying #{status_code} \"#{reason_phrase}\"" if $oversip_debug
|
|
73
|
+
|
|
74
|
+
send_response(response)
|
|
75
|
+
true
|
|
76
|
+
end
|
|
77
|
+
|
|
78
|
+
|
|
79
|
+
def reply_full response
|
|
80
|
+
return false unless @server_transaction.receive_response(response.status_code) if @server_transaction
|
|
81
|
+
|
|
82
|
+
# Ensure the response has Content-Length. Add it otherwise.
|
|
83
|
+
if response.body
|
|
84
|
+
response.headers["Content-Length"] = [ response.body.bytesize.to_s ]
|
|
85
|
+
else
|
|
86
|
+
response.headers["Content-Length"] = HDR_ARRAY_CONTENT_LENGTH_0
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
response_leg_a = response.to_s
|
|
90
|
+
@server_transaction.last_response = response_leg_a if @server_transaction
|
|
91
|
+
|
|
92
|
+
log_system_debug "forwarding response #{response.status_code} \"#{response.reason_phrase}\"" if $oversip_debug
|
|
93
|
+
|
|
94
|
+
send_response(response_leg_a)
|
|
95
|
+
true
|
|
96
|
+
end
|
|
97
|
+
|
|
98
|
+
|
|
99
|
+
def send_response(response)
|
|
100
|
+
unless (case @transport
|
|
101
|
+
when :udp
|
|
102
|
+
@connection.send_sip_msg response, @source_ip, @via_rport || @via_sent_by_port || 5060
|
|
103
|
+
else
|
|
104
|
+
@connection.send_sip_msg response
|
|
105
|
+
end
|
|
106
|
+
)
|
|
107
|
+
log_system_notice "error sending the SIP response"
|
|
108
|
+
end
|
|
109
|
+
end
|
|
110
|
+
|
|
111
|
+
|
|
112
|
+
def to_s
|
|
113
|
+
msg = "#{@sip_method.to_s} #{self.ruri.uri} SIP/2.0\r\n"
|
|
114
|
+
|
|
115
|
+
@headers.each do |key, values|
|
|
116
|
+
values.each do |value|
|
|
117
|
+
msg << key << ": #{value}\r\n"
|
|
118
|
+
end
|
|
119
|
+
end
|
|
120
|
+
|
|
121
|
+
msg << CRLF
|
|
122
|
+
msg << @body if @body
|
|
123
|
+
msg
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
end # class Request
|
|
127
|
+
|
|
128
|
+
end
|
|
@@ -0,0 +1,30 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class Response < Message
|
|
4
|
+
|
|
5
|
+
attr_accessor :status_code
|
|
6
|
+
attr_accessor :reason_phrase
|
|
7
|
+
attr_accessor :request # The associated request.
|
|
8
|
+
|
|
9
|
+
|
|
10
|
+
def request? ; false end
|
|
11
|
+
def response? ; true end
|
|
12
|
+
|
|
13
|
+
|
|
14
|
+
def to_s
|
|
15
|
+
msg = "SIP/2.0 #{@status_code} #{@reason_phrase}\r\n"
|
|
16
|
+
|
|
17
|
+
@headers.each do |key, values|
|
|
18
|
+
values.each do |value|
|
|
19
|
+
msg << key << ": #{value}\r\n"
|
|
20
|
+
end
|
|
21
|
+
end
|
|
22
|
+
|
|
23
|
+
msg << CRLF
|
|
24
|
+
msg << @body if @body
|
|
25
|
+
msg
|
|
26
|
+
end
|
|
27
|
+
|
|
28
|
+
end # class Response
|
|
29
|
+
|
|
30
|
+
end
|