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,213 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class UdpReactor < Reactor
|
|
4
|
+
|
|
5
|
+
def receive_data data
|
|
6
|
+
@buffer << data
|
|
7
|
+
|
|
8
|
+
while (case @state
|
|
9
|
+
when :init
|
|
10
|
+
@parser.reset
|
|
11
|
+
@parser_nbytes = 0
|
|
12
|
+
@state = :message
|
|
13
|
+
|
|
14
|
+
when :message
|
|
15
|
+
parse_message
|
|
16
|
+
|
|
17
|
+
when :finished
|
|
18
|
+
# Invoke the custom logic for requests.
|
|
19
|
+
if @msg.request?
|
|
20
|
+
process_request
|
|
21
|
+
else
|
|
22
|
+
process_response
|
|
23
|
+
end
|
|
24
|
+
@state = :init
|
|
25
|
+
false
|
|
26
|
+
end)
|
|
27
|
+
end # while
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
def parse_message
|
|
31
|
+
return false if @buffer.empty?
|
|
32
|
+
|
|
33
|
+
buffer_str = @buffer.to_str
|
|
34
|
+
|
|
35
|
+
# Quikly ignore single CRLF (widely used by SIP UDP clients as keep-alive.
|
|
36
|
+
if buffer_str == CRLF
|
|
37
|
+
@buffer.clear
|
|
38
|
+
@state = :init
|
|
39
|
+
return false
|
|
40
|
+
end
|
|
41
|
+
|
|
42
|
+
begin
|
|
43
|
+
source_port, source_ip = ::Socket.unpack_sockaddr_in(get_peername)
|
|
44
|
+
rescue => e
|
|
45
|
+
log_system_crit "error obtaining remote IP/port (#{e.class}: #{e.message})"
|
|
46
|
+
@buffer.clear
|
|
47
|
+
@state = :init
|
|
48
|
+
return false
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
case stun_res = ::OverSIP::Stun.parse_request(buffer_str, source_ip, source_port)
|
|
52
|
+
# Not a STUN request so continue with SIP parsing.
|
|
53
|
+
when nil
|
|
54
|
+
# An invalid STUN request, log it and drop it.
|
|
55
|
+
when false
|
|
56
|
+
log_system_debug "invalid STUN message received (not a valid STUN Binding Request)" if $oversip_debug
|
|
57
|
+
@buffer.clear
|
|
58
|
+
@state = :init
|
|
59
|
+
return false
|
|
60
|
+
# A valid STUN Binding Request so we get a response to be sent.
|
|
61
|
+
when String
|
|
62
|
+
log_system_debug "STUN Binding Request received, replying to it" if $oversip_debug
|
|
63
|
+
send_data stun_res
|
|
64
|
+
@buffer.clear
|
|
65
|
+
@state = :init
|
|
66
|
+
return false
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
# Parse the currently buffered data. If parsing fails @parser_nbytes gets nil value.
|
|
70
|
+
unless @parser_nbytes = @parser.execute(buffer_str, @parser_nbytes)
|
|
71
|
+
# The parsed data is invalid, however some data could be parsed so @parsed.parsed
|
|
72
|
+
# can be:
|
|
73
|
+
# - SIP::Request
|
|
74
|
+
# - SIP::Response
|
|
75
|
+
# - nil (the message is so wrong that cannot be neither a request or response).
|
|
76
|
+
if wrong_message = @parser.parsed
|
|
77
|
+
log_system_warn "parsing error for #{MSG_TYPE[wrong_message.class]}: \"#{@parser.error}\""
|
|
78
|
+
else
|
|
79
|
+
log_system_warn "parsing error: \"#{@parser.error}\""
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
@buffer.clear
|
|
83
|
+
@state = :init
|
|
84
|
+
return false
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
unless @parser.finished?
|
|
88
|
+
# The parsing has not finished.
|
|
89
|
+
# If UDP it's invalid as per RFC 3261 a UDP datagram MUST contain an entire
|
|
90
|
+
# SIP request or response. Note we also allow double CRLF in UDP. If just a
|
|
91
|
+
# single CRLF arrives ignore it and clear the buffer.
|
|
92
|
+
# Maybe the parser has gone enought data to determine if the unfinished
|
|
93
|
+
# message is a SIP request or response, log it if so.
|
|
94
|
+
# If not, then @parser.parsed returns nil and nothing is logged.
|
|
95
|
+
unfinished_msg = @parser.parsed
|
|
96
|
+
log_system_warn "ignoring not finished #{MSG_TYPE[unfinished_msg.class]} via UDP" if
|
|
97
|
+
unfinished_msg.is_a? ::OverSIP::SIP::Request or unfinished_msg.is_a? ::OverSIP::SIP::Response
|
|
98
|
+
# Clear the buffer, set :init state and wait for new messages.
|
|
99
|
+
@buffer.clear
|
|
100
|
+
@state = :init
|
|
101
|
+
return false
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
# At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol.
|
|
105
|
+
@msg = @parser.parsed
|
|
106
|
+
|
|
107
|
+
# Clear parsed data from the buffer.
|
|
108
|
+
@buffer.read(@parser_nbytes)
|
|
109
|
+
|
|
110
|
+
# Received data is a Outbound keealive (also allowed in UDP however). Reply single CRLF.
|
|
111
|
+
if @msg == :outbound_keepalive
|
|
112
|
+
log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug
|
|
113
|
+
# Reply a single CRLF over the same connection.
|
|
114
|
+
send_data CRLF
|
|
115
|
+
# If UDP there could be invalid data after double CRLF CRLF, just ignore it
|
|
116
|
+
# and clear the buffer. Set :init state and return false so we leave receive_data()
|
|
117
|
+
# method.
|
|
118
|
+
@buffer.clear
|
|
119
|
+
@state = :init
|
|
120
|
+
return false
|
|
121
|
+
end
|
|
122
|
+
|
|
123
|
+
@parser.post_parsing
|
|
124
|
+
|
|
125
|
+
# Here we have received the entire headers of a SIP request or response. Fill some
|
|
126
|
+
# attributes.
|
|
127
|
+
@msg.connection = self
|
|
128
|
+
@msg.transport = :udp
|
|
129
|
+
@msg.source_ip = source_ip
|
|
130
|
+
@msg.source_port = source_port
|
|
131
|
+
@msg.source_ip_type = self.class.ip_type
|
|
132
|
+
|
|
133
|
+
unless valid_message?
|
|
134
|
+
@buffer.clear
|
|
135
|
+
@state = :init
|
|
136
|
+
return false
|
|
137
|
+
end
|
|
138
|
+
|
|
139
|
+
add_via_received_rport if @msg.request?
|
|
140
|
+
|
|
141
|
+
unless check_via_branch
|
|
142
|
+
@buffer.clear
|
|
143
|
+
@state = :init
|
|
144
|
+
return false
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Examine Content-Length header.
|
|
148
|
+
# There is Content-Length header.
|
|
149
|
+
if cl = @msg.content_length and cl > 0
|
|
150
|
+
# Body size is correct. Read it and clear the buffer.
|
|
151
|
+
# Set :finished state and return true so message will be processed.
|
|
152
|
+
if cl == @buffer.size
|
|
153
|
+
@msg.body = @buffer.read.force_encoding(::Encoding::UTF_8)
|
|
154
|
+
@buffer.clear
|
|
155
|
+
@state = :finished
|
|
156
|
+
return true
|
|
157
|
+
# In UDP the remaining data after headers must be the entire body
|
|
158
|
+
# and fill exactly Content-Length bytes. If not it's invalid. Reply
|
|
159
|
+
# 400 and clear the buffer.
|
|
160
|
+
else
|
|
161
|
+
if @msg.request?
|
|
162
|
+
unless @msg.sip_method == :ACK
|
|
163
|
+
log_system_warn "request body size doesn't match Content-Length => 400"
|
|
164
|
+
@msg.reply 400, "Body size doesn't match Content-Length"
|
|
165
|
+
else
|
|
166
|
+
log_system_warn "ACK body size doesn't match Content-Length, ignoring it"
|
|
167
|
+
end
|
|
168
|
+
else
|
|
169
|
+
log_system_warn "response body size doesn't match Content-Length, ignoring it"
|
|
170
|
+
end
|
|
171
|
+
@buffer.clear
|
|
172
|
+
@state = :init
|
|
173
|
+
return false
|
|
174
|
+
end
|
|
175
|
+
# No Content-Length header or 0 value. However it could occur that the datagram
|
|
176
|
+
# contains remaining unuseful data, in this case reply 400. If not
|
|
177
|
+
# set :finished state and return true so message will be processed.
|
|
178
|
+
else
|
|
179
|
+
# Ensure there is no more data in the buffer. If it's ok set :finished
|
|
180
|
+
# state and return true so message will be processed.
|
|
181
|
+
if @buffer.size.zero?
|
|
182
|
+
@state = :finished
|
|
183
|
+
return true
|
|
184
|
+
# Non valid remaining data in the UDP datagram. Reply 400.
|
|
185
|
+
else
|
|
186
|
+
if @msg.request?
|
|
187
|
+
log_system_warn "request contains body but Content-Length is zero or not present => 400"
|
|
188
|
+
@msg.reply 400, "request contains body but Content-Length is zero or not present"
|
|
189
|
+
else
|
|
190
|
+
log_system_warn "response contains body but Content-Length is zero or not present, ignoring it"
|
|
191
|
+
end
|
|
192
|
+
@buffer.clear
|
|
193
|
+
@state = :init
|
|
194
|
+
return false
|
|
195
|
+
end
|
|
196
|
+
end
|
|
197
|
+
|
|
198
|
+
end # parse_headers
|
|
199
|
+
|
|
200
|
+
def send_sip_msg msg, ip, port
|
|
201
|
+
send_datagram msg, ip, port
|
|
202
|
+
true
|
|
203
|
+
end
|
|
204
|
+
|
|
205
|
+
|
|
206
|
+
def unbind cause=nil
|
|
207
|
+
log_system_crit "UDP socket closed!!! cause: #{cause.inspect}"
|
|
208
|
+
end
|
|
209
|
+
|
|
210
|
+
end # class UdpReactor
|
|
211
|
+
|
|
212
|
+
end
|
|
213
|
+
|
|
@@ -0,0 +1,28 @@
|
|
|
1
|
+
# OverSIP files
|
|
2
|
+
|
|
3
|
+
require "oversip/sip/listeners/reactor"
|
|
4
|
+
|
|
5
|
+
require "oversip/sip/listeners/udp_reactor"
|
|
6
|
+
require "oversip/sip/listeners/tcp_reactor"
|
|
7
|
+
require "oversip/sip/listeners/tls_tunnel_reactor"
|
|
8
|
+
|
|
9
|
+
require "oversip/sip/listeners/tcp_server"
|
|
10
|
+
require "oversip/sip/listeners/tls_server"
|
|
11
|
+
require "oversip/sip/listeners/tls_tunnel_server"
|
|
12
|
+
|
|
13
|
+
require "oversip/sip/listeners/ipv4_udp_server"
|
|
14
|
+
require "oversip/sip/listeners/ipv6_udp_server"
|
|
15
|
+
require "oversip/sip/listeners/ipv4_tcp_server"
|
|
16
|
+
require "oversip/sip/listeners/ipv6_tcp_server"
|
|
17
|
+
require "oversip/sip/listeners/ipv4_tls_server"
|
|
18
|
+
require "oversip/sip/listeners/ipv6_tls_server"
|
|
19
|
+
require "oversip/sip/listeners/ipv4_tls_tunnel_server"
|
|
20
|
+
require "oversip/sip/listeners/ipv6_tls_tunnel_server"
|
|
21
|
+
|
|
22
|
+
require "oversip/sip/listeners/tcp_client"
|
|
23
|
+
require "oversip/sip/listeners/tls_client"
|
|
24
|
+
|
|
25
|
+
require "oversip/sip/listeners/ipv4_tcp_client"
|
|
26
|
+
require "oversip/sip/listeners/ipv6_tcp_client"
|
|
27
|
+
require "oversip/sip/listeners/ipv4_tls_client"
|
|
28
|
+
require "oversip/sip/listeners/ipv6_tls_client"
|
|
@@ -0,0 +1,168 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class Message
|
|
4
|
+
|
|
5
|
+
include ::OverSIP::Logger
|
|
6
|
+
|
|
7
|
+
DIALOG_FORMING_METHODS = { :INVITE=>true, :SUBSCRIBE=>true, :REFER=>true }
|
|
8
|
+
LOOSE_RECORD_AWARE_METHODS = { :INVITE=>true, :REGISTER=>true, :SUBSCRIBE=>true, :REFER=>true }
|
|
9
|
+
OUTBOUND_AWARE_METHODS = { :INVITE=>true, :REGISTER=>true, :SUBSCRIBE=>true, :REFER=>true }
|
|
10
|
+
EMPTY_ARRAY = [].freeze
|
|
11
|
+
|
|
12
|
+
# SIP related attributes.
|
|
13
|
+
attr_accessor :transport
|
|
14
|
+
attr_accessor :source_ip
|
|
15
|
+
attr_accessor :source_ip_type
|
|
16
|
+
attr_accessor :source_port
|
|
17
|
+
attr_accessor :connection
|
|
18
|
+
|
|
19
|
+
# SIP message attributes.
|
|
20
|
+
attr_reader :sip_method
|
|
21
|
+
attr_reader :sip_version
|
|
22
|
+
attr_reader :headers
|
|
23
|
+
|
|
24
|
+
attr_reader :via_sent_by_host
|
|
25
|
+
attr_reader :via_sent_by_port
|
|
26
|
+
attr_reader :via_branch
|
|
27
|
+
attr_accessor :via_branch_id # It's the branch value without "z9hG4bK".
|
|
28
|
+
attr_reader :via_branch_rfc3261
|
|
29
|
+
attr_reader :via_received
|
|
30
|
+
attr_reader :via_has_rport
|
|
31
|
+
attr_accessor :via_rport # Value not parsed.
|
|
32
|
+
attr_reader :via_has_alias
|
|
33
|
+
attr_reader :via_core_value
|
|
34
|
+
attr_reader :via_params
|
|
35
|
+
attr_reader :num_vias
|
|
36
|
+
|
|
37
|
+
attr_reader :call_id
|
|
38
|
+
attr_reader :cseq
|
|
39
|
+
attr_reader :max_forwards
|
|
40
|
+
attr_reader :content_length
|
|
41
|
+
attr_reader :routes
|
|
42
|
+
attr_reader :require
|
|
43
|
+
attr_reader :supported
|
|
44
|
+
attr_reader :proxy_require
|
|
45
|
+
|
|
46
|
+
attr_accessor :body
|
|
47
|
+
|
|
48
|
+
attr_accessor :from # NameAddr instance.
|
|
49
|
+
attr_reader :from_tag
|
|
50
|
+
attr_accessor :to # NameAddr instance.
|
|
51
|
+
attr_reader :to_tag
|
|
52
|
+
attr_reader :contact # NameAddr instance (when it has a single value).
|
|
53
|
+
attr_reader :contact_params
|
|
54
|
+
|
|
55
|
+
attr_reader :hdr_via # Array
|
|
56
|
+
attr_reader :hdr_from # String
|
|
57
|
+
attr_reader :hdr_to # String
|
|
58
|
+
attr_reader :hdr_route # Array
|
|
59
|
+
|
|
60
|
+
# Other attributes.
|
|
61
|
+
attr_accessor :tvars # Transaction variables (a hash).
|
|
62
|
+
|
|
63
|
+
|
|
64
|
+
def udp? ; @transport == :udp end
|
|
65
|
+
def tcp? ; @transport == :tcp end
|
|
66
|
+
def tls? ; @transport == :tls end
|
|
67
|
+
def ws? ; @transport == :ws end
|
|
68
|
+
def tls? ; @transport == :wss end
|
|
69
|
+
|
|
70
|
+
def websocket? ; @transport == :ws || @transport == :wss end
|
|
71
|
+
|
|
72
|
+
def unknown_method? ; @is_unknown_method end
|
|
73
|
+
|
|
74
|
+
def via_rport? ; @via_has_rport end
|
|
75
|
+
|
|
76
|
+
def via_alias? ; @via_has_alias end
|
|
77
|
+
|
|
78
|
+
def dialog_forming?
|
|
79
|
+
DIALOG_FORMING_METHODS[@sip_method]
|
|
80
|
+
end
|
|
81
|
+
|
|
82
|
+
def loose_record_aware?
|
|
83
|
+
LOOSE_RECORD_AWARE_METHODS[@sip_method]
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
def outbound_aware?
|
|
87
|
+
OUTBOUND_AWARE_METHODS[@sip_method]
|
|
88
|
+
end
|
|
89
|
+
|
|
90
|
+
# Returns true if a header with the given header _name_ exists, false otherwise.
|
|
91
|
+
def has_header? name
|
|
92
|
+
@headers[MessageParser.headerize(name)] && true
|
|
93
|
+
end
|
|
94
|
+
|
|
95
|
+
# Returns the first value of the given header _name_, nil if it doesn't exist.
|
|
96
|
+
def header_top name
|
|
97
|
+
( hdr = @headers[MessageParser.headerize(name)] ) ? hdr[0] : nil
|
|
98
|
+
end
|
|
99
|
+
alias :header :header_top
|
|
100
|
+
|
|
101
|
+
# Returns an array with all the values of the given header _name_, an empty array
|
|
102
|
+
# if it doesn't exist.
|
|
103
|
+
def header_all name
|
|
104
|
+
( hdr = @headers[MessageParser.headerize(name)] ) ? hdr : EMPTY_ARRAY
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# Replaces the header of given _name_ with a the given _value_.
|
|
108
|
+
# _value_ can be a single value or an array.
|
|
109
|
+
def set_header name, value
|
|
110
|
+
@headers[MessageParser.headerize(name)] =
|
|
111
|
+
case value
|
|
112
|
+
when Array
|
|
113
|
+
value
|
|
114
|
+
else
|
|
115
|
+
[ value.to_s ]
|
|
116
|
+
end
|
|
117
|
+
end
|
|
118
|
+
|
|
119
|
+
# Completely deletes the header with given _name_.
|
|
120
|
+
# Returns an array containing all the header values, nil otherwise.
|
|
121
|
+
def delete_header name
|
|
122
|
+
@headers.delete MessageParser.headerize(name)
|
|
123
|
+
end
|
|
124
|
+
|
|
125
|
+
# Removes the first value of a given header _name_.
|
|
126
|
+
# Returns the extracted value, nil otherwise.
|
|
127
|
+
def delete_header_top name
|
|
128
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
129
|
+
hdr.size > 1 ? hdr.shift : @headers.delete(k)[0]
|
|
130
|
+
end
|
|
131
|
+
end
|
|
132
|
+
|
|
133
|
+
# Inserts the given _value_ in the first position of header _name_.
|
|
134
|
+
# _value_ must be a string.
|
|
135
|
+
def insert_header name, value
|
|
136
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
137
|
+
hdr.insert 0, value.to_s
|
|
138
|
+
else
|
|
139
|
+
#@headers[k] = [ value.to_s ]
|
|
140
|
+
# NOTE: If the header name doesn't already exist in the mesage, insert
|
|
141
|
+
# the new header in the first position of the Hash.
|
|
142
|
+
@headers = { k => [ value.to_s ] }.merge! @headers
|
|
143
|
+
end
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Append the given _value_ in the last position of header _name_.
|
|
147
|
+
# _value_ must be a string.
|
|
148
|
+
def append_header name, value
|
|
149
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
150
|
+
hdr.push value.to_s
|
|
151
|
+
else
|
|
152
|
+
@headers[k] = [ value.to_s ]
|
|
153
|
+
end
|
|
154
|
+
end
|
|
155
|
+
|
|
156
|
+
# Replaces the top value of the given header _name_ with the
|
|
157
|
+
# string given as argument _value_.
|
|
158
|
+
def replace_header_top name, value
|
|
159
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
160
|
+
hdr[0] = value.to_s
|
|
161
|
+
else
|
|
162
|
+
@headers[k] = [ value.to_s ]
|
|
163
|
+
end
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
end # class Message
|
|
167
|
+
|
|
168
|
+
end
|
|
@@ -0,0 +1,202 @@
|
|
|
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?
|
|
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
|
+
# Create a new Logic instance for this request (unless it's a retransmission of the request,
|
|
77
|
+
# a CANCEL or an ACK for a final non-2XX response).
|
|
78
|
+
unless check_transaction
|
|
79
|
+
begin
|
|
80
|
+
# Create the antiloop identifier for this request.
|
|
81
|
+
@msg.antiloop_id = ::OverSIP::SIP::Tags.create_antiloop_id(@msg)
|
|
82
|
+
|
|
83
|
+
# Check loops.
|
|
84
|
+
if @msg.antiloop_id == @msg.via_branch_id[-32..-1]
|
|
85
|
+
@msg.reply 482, "Loop Detected"
|
|
86
|
+
return
|
|
87
|
+
end
|
|
88
|
+
|
|
89
|
+
# Initialize some attributes for the request (for received responses
|
|
90
|
+
# it's set in Proxy#receive_response).
|
|
91
|
+
@msg.tvars = {}
|
|
92
|
+
|
|
93
|
+
# Create the Logic instance and run it!
|
|
94
|
+
OverSIP::SIP::Logic.new(@msg).run
|
|
95
|
+
rescue => e
|
|
96
|
+
log_system_error e
|
|
97
|
+
@msg.reply 503, "Internal Error", ["Content-Type: text/plain"], "#{e.class }: #{e.message}"
|
|
98
|
+
end
|
|
99
|
+
end
|
|
100
|
+
end
|
|
101
|
+
private :process_request
|
|
102
|
+
|
|
103
|
+
|
|
104
|
+
# Process a received response.
|
|
105
|
+
def process_response
|
|
106
|
+
case @msg.sip_method
|
|
107
|
+
when :INVITE
|
|
108
|
+
### TODO: Esto va a petar cuando tenga una clase que hereda de, p.ej, IPv4TcpServer que se llame xxxClient,
|
|
109
|
+
# ya que en ella no existirá @invite_client_transactions. Tengo que hacer que su @invite_client_transactions
|
|
110
|
+
# se rellene al de la clase padre al hacer el load de las clases.
|
|
111
|
+
if client_transaction = self.class.invite_client_transactions[@msg.via_branch_id]
|
|
112
|
+
client_transaction.receive_response(@msg)
|
|
113
|
+
return
|
|
114
|
+
end
|
|
115
|
+
when :ACK
|
|
116
|
+
when :CANCEL
|
|
117
|
+
if client_transaction = self.class.invite_client_transactions[@msg.via_branch_id]
|
|
118
|
+
client_transaction.receive_response_to_cancel(@msg)
|
|
119
|
+
return
|
|
120
|
+
end
|
|
121
|
+
else
|
|
122
|
+
if client_transaction = self.class.non_invite_client_transactions[@msg.via_branch_id]
|
|
123
|
+
client_transaction.receive_response(@msg)
|
|
124
|
+
return
|
|
125
|
+
end
|
|
126
|
+
end
|
|
127
|
+
log_system_debug "ignoring a response non matching a client transaction (#{@msg.sip_method} #{@msg.status_code})" if $oversip_debug
|
|
128
|
+
end
|
|
129
|
+
private :process_response
|
|
130
|
+
|
|
131
|
+
|
|
132
|
+
# Check transaction.
|
|
133
|
+
def check_transaction
|
|
134
|
+
case @msg.sip_method
|
|
135
|
+
|
|
136
|
+
when :INVITE
|
|
137
|
+
if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
|
|
138
|
+
# If the retranmission arrives via a different connection (for TCP/TLS) then use
|
|
139
|
+
# the new one.
|
|
140
|
+
if @msg.connection == server_transaction.request.connection
|
|
141
|
+
log_system_debug "INVITE retransmission received" if $oversip_debug
|
|
142
|
+
else
|
|
143
|
+
log_system_debug "INVITE retransmission received via other connection, updating server transaction" if $oversip_debug
|
|
144
|
+
server_transaction.request.connection = @msg.connection
|
|
145
|
+
end
|
|
146
|
+
server_transaction.retransmit_last_response
|
|
147
|
+
return true
|
|
148
|
+
end
|
|
149
|
+
|
|
150
|
+
when :ACK
|
|
151
|
+
# If there is associated INVITE transaction (so it has been rejected)
|
|
152
|
+
# pass ACK to the transaction.
|
|
153
|
+
if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
|
|
154
|
+
server_transaction.receive_ack
|
|
155
|
+
return true
|
|
156
|
+
# Absorb ACK for statelessly generated final responses by us.
|
|
157
|
+
elsif OverSIP::SIP::Tags.check_totag_for_sl_reply(@msg.to_tag)
|
|
158
|
+
log_system_debug "absorving ACK for a stateless final response" if $oversip_debug
|
|
159
|
+
return true
|
|
160
|
+
else
|
|
161
|
+
log_system_debug "passing ACK to the core" if $oversip_debug
|
|
162
|
+
return false
|
|
163
|
+
end
|
|
164
|
+
|
|
165
|
+
when :CANCEL
|
|
166
|
+
if server_transaction = @msg.connection.class.invite_server_transactions[@msg.via_branch_id]
|
|
167
|
+
case state = server_transaction.state
|
|
168
|
+
when :proceeding
|
|
169
|
+
log_system_debug "CANCEL matches an INVITE server transaction in proceeding state => 200" if $oversip_debug
|
|
170
|
+
@msg.reply 200, "Cancelled"
|
|
171
|
+
server_transaction.receive_cancel(@msg)
|
|
172
|
+
else
|
|
173
|
+
log_system_debug "CANCEL matches an INVITE server transaction in #{state} state => 200" if $oversip_debug
|
|
174
|
+
@msg.reply 200, "Cancelled"
|
|
175
|
+
end
|
|
176
|
+
else
|
|
177
|
+
log_system_debug "CANCEL does not match an INVITE server transaction => 481" if $oversip_debug
|
|
178
|
+
@msg.reply 481
|
|
179
|
+
end
|
|
180
|
+
return true
|
|
181
|
+
|
|
182
|
+
else
|
|
183
|
+
if server_transaction = @msg.connection.class.non_invite_server_transactions[@msg.via_branch_id]
|
|
184
|
+
# If the retranmission arrives via a different connection (for TCP/TLS) then use
|
|
185
|
+
# the new one.
|
|
186
|
+
if @msg.connection == server_transaction.request.connection
|
|
187
|
+
log_system_debug "#{server_transaction.request.sip_method} retransmission received" if $oversip_debug
|
|
188
|
+
else
|
|
189
|
+
log_system_debug "#{server_transaction.request.sip_method} retransmission received via other connection, updating server transaction" if $oversip_debug
|
|
190
|
+
server_transaction.request.connection = @msg.connection
|
|
191
|
+
end
|
|
192
|
+
server_transaction.retransmit_last_response
|
|
193
|
+
return true
|
|
194
|
+
end
|
|
195
|
+
|
|
196
|
+
end
|
|
197
|
+
end # def check_transaction
|
|
198
|
+
private :check_transaction
|
|
199
|
+
|
|
200
|
+
end
|
|
201
|
+
|
|
202
|
+
end
|