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,89 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class TlsTunnelConnection < TcpConnection
|
|
4
|
+
|
|
5
|
+
# Max size (bytes) of the buffered data when receiving message headers
|
|
6
|
+
# (avoid DoS attacks).
|
|
7
|
+
HEADERS_MAX_SIZE = 16384
|
|
8
|
+
|
|
9
|
+
def process_received_data
|
|
10
|
+
@state == :ignore and return
|
|
11
|
+
|
|
12
|
+
while (case @state
|
|
13
|
+
when :init
|
|
14
|
+
@parser.reset
|
|
15
|
+
@parser_nbytes = 0
|
|
16
|
+
# If it's a TCP connection from the TLS tunnel then parse the HAProxy Protocol line
|
|
17
|
+
# if it's not yet done.
|
|
18
|
+
unless @haproxy_protocol_parsed
|
|
19
|
+
@state = :haproxy_protocol
|
|
20
|
+
else
|
|
21
|
+
@state = :headers
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
when :haproxy_protocol
|
|
25
|
+
parse_haproxy_protocol
|
|
26
|
+
|
|
27
|
+
when :headers
|
|
28
|
+
parse_headers
|
|
29
|
+
|
|
30
|
+
when :body
|
|
31
|
+
get_body
|
|
32
|
+
|
|
33
|
+
when :finished
|
|
34
|
+
if @msg.request?
|
|
35
|
+
process_request
|
|
36
|
+
else
|
|
37
|
+
process_response
|
|
38
|
+
end
|
|
39
|
+
|
|
40
|
+
# Set state to :init.
|
|
41
|
+
@state = :init
|
|
42
|
+
# Return true to continue processing possible remaining data.
|
|
43
|
+
true
|
|
44
|
+
|
|
45
|
+
when :ignore
|
|
46
|
+
false
|
|
47
|
+
end)
|
|
48
|
+
end # while
|
|
49
|
+
|
|
50
|
+
end
|
|
51
|
+
|
|
52
|
+
def parse_haproxy_protocol
|
|
53
|
+
if (haproxy_protocol_data = ::OverSIP::Utils.parse_haproxy_protocol(@buffer.to_str))
|
|
54
|
+
@haproxy_protocol_parsed = true
|
|
55
|
+
|
|
56
|
+
# Update connection information.
|
|
57
|
+
@remote_ip_type = haproxy_protocol_data[1]
|
|
58
|
+
@remote_ip = haproxy_protocol_data[2]
|
|
59
|
+
@remote_port = haproxy_protocol_data[3]
|
|
60
|
+
|
|
61
|
+
# Add the connection with the client's source data. Note that we pass a TlsServer as class, but
|
|
62
|
+
# the server instance is a TcpServer.
|
|
63
|
+
@connection_id = case @remote_ip_type
|
|
64
|
+
when :ipv4
|
|
65
|
+
::OverSIP::SIP::TransportManager.add_connection self, ::OverSIP::SIP::IPv4TlsServer, :ipv4, @remote_ip, @remote_port
|
|
66
|
+
when :ipv6
|
|
67
|
+
::OverSIP::SIP::TransportManager.add_connection self, ::OverSIP::SIP::IPv6TlsServer, :ipv6, @remote_ip, @remote_port
|
|
68
|
+
end
|
|
69
|
+
|
|
70
|
+
# Update log information.
|
|
71
|
+
remote_desc true
|
|
72
|
+
|
|
73
|
+
# Remove the HAProxy Protocol line from the received data.
|
|
74
|
+
@buffer.read haproxy_protocol_data[0]
|
|
75
|
+
|
|
76
|
+
@state = :headers
|
|
77
|
+
|
|
78
|
+
else
|
|
79
|
+
log_system_error "HAProxy Protocol parsing error, closing connection"
|
|
80
|
+
close_connection_after_writing
|
|
81
|
+
@state = :ignore
|
|
82
|
+
return false
|
|
83
|
+
end
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
end
|
|
89
|
+
|
|
@@ -0,0 +1,61 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class TlsTunnelServer < TlsTunnelConnection
|
|
4
|
+
|
|
5
|
+
attr_reader :outbound_flow_token
|
|
6
|
+
|
|
7
|
+
def post_connection
|
|
8
|
+
begin
|
|
9
|
+
# Temporal @remote_ip and @remote_port until the HAProxy protocol line is parsed.
|
|
10
|
+
@remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
|
|
11
|
+
rescue => e
|
|
12
|
+
log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
|
|
13
|
+
close_connection
|
|
14
|
+
@state = :ignore
|
|
15
|
+
return
|
|
16
|
+
end
|
|
17
|
+
|
|
18
|
+
# Create an Outbound (RFC 5626) flow token for this connection.
|
|
19
|
+
@outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
|
|
20
|
+
|
|
21
|
+
log_system_debug ("connection from the TLS tunnel " << remote_desc) if $oversip_debug
|
|
22
|
+
end
|
|
23
|
+
|
|
24
|
+
def remote_desc force=nil
|
|
25
|
+
if force
|
|
26
|
+
@remote_desc = case @remote_ip_type
|
|
27
|
+
when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
|
|
28
|
+
when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
|
|
29
|
+
end
|
|
30
|
+
else
|
|
31
|
+
@remote_desc ||= case self.class.ip_type
|
|
32
|
+
when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
|
|
33
|
+
when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
|
|
34
|
+
end
|
|
35
|
+
end
|
|
36
|
+
end
|
|
37
|
+
|
|
38
|
+
|
|
39
|
+
def unbind cause=nil
|
|
40
|
+
@state = :ignore
|
|
41
|
+
|
|
42
|
+
# Remove the connection.
|
|
43
|
+
self.class.connections.delete @connection_id if @connection_id
|
|
44
|
+
|
|
45
|
+
# Remove the Outbound token flow.
|
|
46
|
+
::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
|
|
47
|
+
|
|
48
|
+
@local_closed = true if cause == ::Errno::ETIMEDOUT
|
|
49
|
+
|
|
50
|
+
if $oversip_debug
|
|
51
|
+
log_msg = "connection from the TLS tunnel #{remote_desc} "
|
|
52
|
+
log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
|
|
53
|
+
log_msg << " (cause: #{cause.inspect})" if cause
|
|
54
|
+
log_system_debug log_msg
|
|
55
|
+
end unless $!
|
|
56
|
+
end
|
|
57
|
+
|
|
58
|
+
end
|
|
59
|
+
|
|
60
|
+
end
|
|
61
|
+
|
|
@@ -0,0 +1,214 @@
|
|
|
1
|
+
module OverSIP::SIP
|
|
2
|
+
|
|
3
|
+
class UdpConnection < Connection
|
|
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
|
+
if @msg.request?
|
|
19
|
+
process_request
|
|
20
|
+
else
|
|
21
|
+
process_response
|
|
22
|
+
end
|
|
23
|
+
@state = :init
|
|
24
|
+
false
|
|
25
|
+
end)
|
|
26
|
+
end # while
|
|
27
|
+
end
|
|
28
|
+
|
|
29
|
+
def parse_message
|
|
30
|
+
return false if @buffer.empty?
|
|
31
|
+
|
|
32
|
+
buffer_str = @buffer.to_str
|
|
33
|
+
|
|
34
|
+
# Quikly ignore single CRLF (widely used by SIP UDP clients as keep-alive).
|
|
35
|
+
if buffer_str == CRLF
|
|
36
|
+
@buffer.clear
|
|
37
|
+
@state = :init
|
|
38
|
+
return false
|
|
39
|
+
end
|
|
40
|
+
|
|
41
|
+
begin
|
|
42
|
+
source_port, source_ip = ::Socket.unpack_sockaddr_in(get_peername)
|
|
43
|
+
rescue => e
|
|
44
|
+
log_system_crit "error obtaining remote IP/port (#{e.class}: #{e.message})"
|
|
45
|
+
@buffer.clear
|
|
46
|
+
@state = :init
|
|
47
|
+
return false
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
case stun_res = ::OverSIP::Stun.parse_request(buffer_str, source_ip, source_port)
|
|
51
|
+
# Not a STUN request so continue with SIP parsing.
|
|
52
|
+
when nil
|
|
53
|
+
# An invalid STUN request, log it and drop it.
|
|
54
|
+
when false
|
|
55
|
+
log_system_debug "invalid STUN message received (not a valid STUN Binding Request)" if $oversip_debug
|
|
56
|
+
@buffer.clear
|
|
57
|
+
@state = :init
|
|
58
|
+
return false
|
|
59
|
+
# A valid STUN Binding Request so we get a response to be sent.
|
|
60
|
+
when ::String
|
|
61
|
+
log_system_debug "STUN Binding Request received, replying to it" if $oversip_debug
|
|
62
|
+
send_data stun_res
|
|
63
|
+
@buffer.clear
|
|
64
|
+
@state = :init
|
|
65
|
+
return false
|
|
66
|
+
end
|
|
67
|
+
|
|
68
|
+
# Parse the currently buffered data. If parsing fails @parser_nbytes gets nil value.
|
|
69
|
+
unless @parser_nbytes = @parser.execute(buffer_str, @parser_nbytes)
|
|
70
|
+
# The parsed data is invalid, however some data could be parsed so @parsed.parsed
|
|
71
|
+
# can be:
|
|
72
|
+
# - SIP::Request
|
|
73
|
+
# - SIP::Response
|
|
74
|
+
# - nil (the message is so wrong that cannot be neither a request or response).
|
|
75
|
+
if wrong_message = @parser.parsed
|
|
76
|
+
log_system_warn "parsing error for #{MSG_TYPE[wrong_message.class]}: \"#{@parser.error}\""
|
|
77
|
+
else
|
|
78
|
+
log_system_warn "parsing error: \"#{@parser.error}\""
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
@buffer.clear
|
|
82
|
+
@state = :init
|
|
83
|
+
return false
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
unless @parser.finished?
|
|
87
|
+
# The parsing has not finished.
|
|
88
|
+
# If UDP it's invalid as per RFC 3261 a UDP datagram MUST contain an entire
|
|
89
|
+
# SIP request or response. Note we also allow double CRLF in UDP. If just a
|
|
90
|
+
# single CRLF arrives ignore it and clear the buffer.
|
|
91
|
+
# Maybe the parser has gone enought data to determine if the unfinished
|
|
92
|
+
# message is a SIP request or response, log it if so.
|
|
93
|
+
# If not, then @parser.parsed returns nil and nothing is logged.
|
|
94
|
+
unfinished_msg = @parser.parsed
|
|
95
|
+
log_system_warn "ignoring not finished #{MSG_TYPE[unfinished_msg.class]} via UDP" if
|
|
96
|
+
unfinished_msg.is_a? ::OverSIP::SIP::Request or unfinished_msg.is_a? ::OverSIP::SIP::Response
|
|
97
|
+
# Clear the buffer, set :init state and wait for new messages.
|
|
98
|
+
@buffer.clear
|
|
99
|
+
@state = :init
|
|
100
|
+
return false
|
|
101
|
+
end
|
|
102
|
+
|
|
103
|
+
# At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol.
|
|
104
|
+
@msg = @parser.parsed
|
|
105
|
+
|
|
106
|
+
# Clear parsed data from the buffer.
|
|
107
|
+
@buffer.read(@parser_nbytes)
|
|
108
|
+
|
|
109
|
+
# Received data is a Outbound keealive (also allowed in UDP however). Reply single CRLF.
|
|
110
|
+
if @msg == :outbound_keepalive
|
|
111
|
+
log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug
|
|
112
|
+
# Reply a single CRLF over the same connection.
|
|
113
|
+
send_data CRLF
|
|
114
|
+
# If UDP there could be invalid data after double CRLF CRLF, just ignore it
|
|
115
|
+
# and clear the buffer. Set :init state and return false so we leave receive_data()
|
|
116
|
+
# method.
|
|
117
|
+
@buffer.clear
|
|
118
|
+
@state = :init
|
|
119
|
+
return false
|
|
120
|
+
end
|
|
121
|
+
|
|
122
|
+
@parser.post_parsing
|
|
123
|
+
|
|
124
|
+
# Here we have received the entire headers of a SIP request or response. Fill some
|
|
125
|
+
# attributes.
|
|
126
|
+
@msg.connection = self
|
|
127
|
+
@msg.transport = :udp
|
|
128
|
+
@msg.source_ip = source_ip
|
|
129
|
+
@msg.source_port = source_port
|
|
130
|
+
@msg.source_ip_type = self.class.ip_type
|
|
131
|
+
|
|
132
|
+
unless valid_message? @parser
|
|
133
|
+
@buffer.clear
|
|
134
|
+
@state = :init
|
|
135
|
+
return false
|
|
136
|
+
end
|
|
137
|
+
|
|
138
|
+
add_via_received_rport if @msg.request?
|
|
139
|
+
|
|
140
|
+
unless check_via_branch
|
|
141
|
+
@buffer.clear
|
|
142
|
+
@state = :init
|
|
143
|
+
return false
|
|
144
|
+
end
|
|
145
|
+
|
|
146
|
+
# Examine Content-Length header.
|
|
147
|
+
# There is Content-Length header.
|
|
148
|
+
if cl = @msg.content_length and cl > 0
|
|
149
|
+
# Body size is correct. Read it and clear the buffer.
|
|
150
|
+
# Set :finished state and return true so message will be processed.
|
|
151
|
+
if cl == @buffer.size
|
|
152
|
+
@msg.body = @buffer.read.force_encoding(::Encoding::UTF_8)
|
|
153
|
+
@buffer.clear
|
|
154
|
+
@state = :finished
|
|
155
|
+
return true
|
|
156
|
+
# In UDP the remaining data after headers must be the entire body
|
|
157
|
+
# and fill exactly Content-Length bytes. If not it's invalid. Reply
|
|
158
|
+
# 400 and clear the buffer.
|
|
159
|
+
else
|
|
160
|
+
if @msg.request?
|
|
161
|
+
unless @msg.sip_method == :ACK
|
|
162
|
+
log_system_warn "request body size doesn't match Content-Length => 400"
|
|
163
|
+
@msg.reply 400, "Body size doesn't match Content-Length"
|
|
164
|
+
else
|
|
165
|
+
log_system_warn "ACK body size doesn't match Content-Length, ignoring it"
|
|
166
|
+
end
|
|
167
|
+
else
|
|
168
|
+
log_system_warn "response body size doesn't match Content-Length, ignoring it"
|
|
169
|
+
end
|
|
170
|
+
@buffer.clear
|
|
171
|
+
@state = :init
|
|
172
|
+
return false
|
|
173
|
+
end
|
|
174
|
+
# No Content-Length header or 0 value. However it could occur that the datagram
|
|
175
|
+
# contains remaining unuseful data, in this case reply 400. If not
|
|
176
|
+
# set :finished state and return true so message will be processed.
|
|
177
|
+
else
|
|
178
|
+
# Ensure there is no more data in the buffer. If it's ok set :finished
|
|
179
|
+
# state and return true so message will be processed.
|
|
180
|
+
if @buffer.size.zero?
|
|
181
|
+
@state = :finished
|
|
182
|
+
return true
|
|
183
|
+
# Non valid remaining data in the UDP datagram. Reply 400.
|
|
184
|
+
else
|
|
185
|
+
if @msg.request?
|
|
186
|
+
log_system_warn "request contains body but Content-Length is zero or not present => 400"
|
|
187
|
+
@msg.reply 400, "request contains body but Content-Length is zero or not present"
|
|
188
|
+
else
|
|
189
|
+
log_system_warn "response contains body but Content-Length is zero or not present, ignoring it"
|
|
190
|
+
end
|
|
191
|
+
@buffer.clear
|
|
192
|
+
@state = :init
|
|
193
|
+
return false
|
|
194
|
+
end
|
|
195
|
+
end
|
|
196
|
+
|
|
197
|
+
end # parse_headers
|
|
198
|
+
|
|
199
|
+
def send_sip_msg msg, ip, port
|
|
200
|
+
send_datagram msg, ip, port
|
|
201
|
+
true
|
|
202
|
+
end
|
|
203
|
+
|
|
204
|
+
|
|
205
|
+
def unbind cause=nil
|
|
206
|
+
unless $!
|
|
207
|
+
log_system_crit "UDP socket closed!!! cause: #{cause.inspect}"
|
|
208
|
+
end
|
|
209
|
+
end
|
|
210
|
+
|
|
211
|
+
end
|
|
212
|
+
|
|
213
|
+
end
|
|
214
|
+
|
|
@@ -0,0 +1,24 @@
|
|
|
1
|
+
# OverSIP files
|
|
2
|
+
|
|
3
|
+
require "oversip/sip/listeners/connection"
|
|
4
|
+
require "oversip/sip/listeners/udp_connection"
|
|
5
|
+
require "oversip/sip/listeners/tcp_connection"
|
|
6
|
+
require "oversip/sip/listeners/tls_tunnel_connection"
|
|
7
|
+
require "oversip/sip/listeners/tcp_server"
|
|
8
|
+
require "oversip/sip/listeners/tls_server"
|
|
9
|
+
require "oversip/sip/listeners/tls_tunnel_server"
|
|
10
|
+
require "oversip/sip/listeners/tcp_client"
|
|
11
|
+
require "oversip/sip/listeners/tls_client"
|
|
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
|
+
require "oversip/sip/listeners/ipv4_tcp_client"
|
|
22
|
+
require "oversip/sip/listeners/ipv6_tcp_client"
|
|
23
|
+
require "oversip/sip/listeners/ipv4_tls_client"
|
|
24
|
+
require "oversip/sip/listeners/ipv6_tls_client"
|
|
@@ -0,0 +1,177 @@
|
|
|
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
|
+
RECORD_ROUTING_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
|
+
def udp? ; @transport == :udp end
|
|
64
|
+
def tcp? ; @transport == :tcp end
|
|
65
|
+
def tls? ; @transport == :tls end
|
|
66
|
+
def ws? ; @transport == :ws end
|
|
67
|
+
def wss? ; @transport == :wss end
|
|
68
|
+
|
|
69
|
+
def websocket? ; @transport == :ws || @transport == :wss end
|
|
70
|
+
|
|
71
|
+
def unknown_method? ; @is_unknown_method end
|
|
72
|
+
|
|
73
|
+
def via_rport? ; @via_has_rport end
|
|
74
|
+
|
|
75
|
+
def via_alias? ; @via_has_alias end
|
|
76
|
+
|
|
77
|
+
def contact_reg_id? ; @contact_has_reg_id end
|
|
78
|
+
|
|
79
|
+
def dialog_forming?
|
|
80
|
+
DIALOG_FORMING_METHODS[@sip_method]
|
|
81
|
+
end
|
|
82
|
+
|
|
83
|
+
def record_routing_aware?
|
|
84
|
+
RECORD_ROUTING_AWARE_METHODS[@sip_method]
|
|
85
|
+
end
|
|
86
|
+
|
|
87
|
+
def outbound_aware?
|
|
88
|
+
OUTBOUND_AWARE_METHODS[@sip_method]
|
|
89
|
+
end
|
|
90
|
+
|
|
91
|
+
# Returns true if a header with the given header _name_ exists, false otherwise.
|
|
92
|
+
def has_header? name
|
|
93
|
+
@headers[MessageParser.headerize(name)] && true
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# Returns the first value of the given header _name_, nil if it doesn't exist.
|
|
97
|
+
def header_top name
|
|
98
|
+
( hdr = @headers[MessageParser.headerize(name)] ) ? hdr[0] : nil
|
|
99
|
+
end
|
|
100
|
+
alias :header :header_top
|
|
101
|
+
|
|
102
|
+
# Returns an array with all the values of the given header _name_, an empty array
|
|
103
|
+
# if it doesn't exist.
|
|
104
|
+
def header_all name
|
|
105
|
+
( hdr = @headers[MessageParser.headerize(name)] ) ? hdr : EMPTY_ARRAY
|
|
106
|
+
end
|
|
107
|
+
|
|
108
|
+
# Replaces the header of given _name_ with a the given _value_.
|
|
109
|
+
# _value_ can be a single value or an array.
|
|
110
|
+
def set_header name, value
|
|
111
|
+
@headers[MessageParser.headerize(name)] =
|
|
112
|
+
case value
|
|
113
|
+
when ::Array
|
|
114
|
+
value
|
|
115
|
+
else
|
|
116
|
+
[ value.to_s ]
|
|
117
|
+
end
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
# Completely deletes the header with given _name_.
|
|
121
|
+
# Returns an array containing all the header values, nil otherwise.
|
|
122
|
+
def delete_header name
|
|
123
|
+
@headers.delete MessageParser.headerize(name)
|
|
124
|
+
end
|
|
125
|
+
|
|
126
|
+
# Removes the first value of a given header _name_.
|
|
127
|
+
# Returns the extracted value, nil otherwise.
|
|
128
|
+
def delete_header_top name
|
|
129
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
130
|
+
hdr.size > 1 ? hdr.shift : @headers.delete(k)[0]
|
|
131
|
+
end
|
|
132
|
+
end
|
|
133
|
+
|
|
134
|
+
# Inserts the given _value_ in the first position of header _name_.
|
|
135
|
+
# _value_ must be a string.
|
|
136
|
+
def insert_header name, value
|
|
137
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
138
|
+
hdr.unshift value.to_s
|
|
139
|
+
else
|
|
140
|
+
#@headers[k] = [ value.to_s ]
|
|
141
|
+
# NOTE: If the header name doesn't already exist in the mesage, insert
|
|
142
|
+
# the new header in the first position of the Hash.
|
|
143
|
+
@headers = { k => [ value.to_s ] }.merge! @headers
|
|
144
|
+
end
|
|
145
|
+
end
|
|
146
|
+
|
|
147
|
+
# Append the given _value_ in the last position of header _name_.
|
|
148
|
+
# _value_ must be a string.
|
|
149
|
+
def append_header name, value
|
|
150
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
151
|
+
hdr.push value.to_s
|
|
152
|
+
else
|
|
153
|
+
@headers[k] = [ value.to_s ]
|
|
154
|
+
end
|
|
155
|
+
end
|
|
156
|
+
|
|
157
|
+
# Replaces the top value of the given header _name_ with the
|
|
158
|
+
# string given as argument _value_.
|
|
159
|
+
def replace_header_top name, value
|
|
160
|
+
if hdr = @headers[k=MessageParser.headerize(name)]
|
|
161
|
+
hdr[0] = value.to_s
|
|
162
|
+
else
|
|
163
|
+
@headers[k] = [ value.to_s ]
|
|
164
|
+
end
|
|
165
|
+
end
|
|
166
|
+
|
|
167
|
+
# Close the connection from which the SIP request/response has been
|
|
168
|
+
# received.
|
|
169
|
+
def close_connection
|
|
170
|
+
return false if @transport == :udp
|
|
171
|
+
@connection.close
|
|
172
|
+
true
|
|
173
|
+
end
|
|
174
|
+
|
|
175
|
+
end # class Message
|
|
176
|
+
|
|
177
|
+
end
|