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.
- checksums.yaml +7 -0
- data/AUTHORS +22 -0
- data/LICENSE +25 -0
- data/README.md +43 -0
- data/Rakefile +54 -0
- data/bin/oversip +184 -0
- data/etc/oversip.conf +274 -0
- data/etc/proxies.conf +145 -0
- data/etc/server.rb +315 -0
- data/etc/tls/ca/cacert.pem +3894 -0
- data/etc/tls/demo-tls.oversip.net.crt +17 -0
- data/etc/tls/demo-tls.oversip.net.key +15 -0
- data/etc/tls/upgrade-cacert.sh +12 -0
- data/etc/tls/utils/create-cert.rb +162 -0
- data/etc/tls/utils/get-sip-identities.rb +95 -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 +210 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_message_parser.c +29741 -0
- data/ext/sip_parser/sip_parser.h +250 -0
- data/ext/sip_parser/sip_parser_ruby.c +1370 -0
- data/ext/sip_parser/sip_uri_parser.c +39699 -0
- data/ext/stud/extconf.rb +43 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +394 -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 +64 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +392 -0
- data/ext/utils/utils_ruby.h +76 -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 +47 -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 +1635 -0
- data/ext/websocket_http_parser/ws_http_parser.h +87 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +597 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/default_server.rb +52 -0
- data/lib/oversip/errors.rb +10 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +635 -0
- data/lib/oversip/logger.rb +84 -0
- data/lib/oversip/modules/outbound_mangling.rb +56 -0
- data/lib/oversip/modules/user_assertion.rb +73 -0
- data/lib/oversip/proxies_config.rb +189 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client.rb +428 -0
- data/lib/oversip/sip/client_transaction.rb +586 -0
- data/lib/oversip/sip/constants.rb +88 -0
- data/lib/oversip/sip/core.rb +217 -0
- data/lib/oversip/sip/launcher.rb +221 -0
- data/lib/oversip/sip/listeners/connection.rb +54 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
- data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +125 -0
- data/lib/oversip/sip/listeners/tls_server.rb +88 -0
- data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
- data/lib/oversip/sip/listeners.rb +24 -0
- data/lib/oversip/sip/message.rb +177 -0
- data/lib/oversip/sip/message_processor.rb +213 -0
- data/lib/oversip/sip/name_addr.rb +51 -0
- data/lib/oversip/sip/proxy.rb +324 -0
- data/lib/oversip/sip/request.rb +179 -0
- data/lib/oversip/sip/response.rb +37 -0
- data/lib/oversip/sip/rfc3263.rb +643 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +76 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +130 -0
- data/lib/oversip/sip/uac.rb +89 -0
- data/lib/oversip/sip/uac_request.rb +84 -0
- data/lib/oversip/sip/uri.rb +208 -0
- data/lib/oversip/syslog.rb +68 -0
- data/lib/oversip/system_callbacks.rb +45 -0
- data/lib/oversip/tls.rb +172 -0
- data/lib/oversip/utils.rb +30 -0
- data/lib/oversip/version.rb +21 -0
- data/lib/oversip/websocket/constants.rb +55 -0
- data/lib/oversip/websocket/http_request.rb +59 -0
- data/lib/oversip/websocket/launcher.rb +183 -0
- data/lib/oversip/websocket/listeners/connection.rb +51 -0
- data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
- data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
- data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
- data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
- data/lib/oversip/websocket/listeners.rb +13 -0
- data/lib/oversip/websocket/websocket.rb +13 -0
- data/lib/oversip/websocket/ws_framing.rb +545 -0
- data/lib/oversip/websocket/ws_sip_app.rb +120 -0
- data/lib/oversip.rb +127 -0
- data/test/oversip_test_helper.rb +19 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_name_addr.rb +27 -0
- data/test/test_name_addr_parser.rb +24 -0
- data/test/test_sip_message_parser.rb +168 -0
- data/test/test_sip_uri_parser.rb +56 -0
- data/test/test_uri.rb +68 -0
- data/thirdparty/stud/stud.tar.gz +0 -0
- 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
|