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.
Files changed (121) hide show
  1. data/AUTHORS.txt +11 -0
  2. data/LICENSE.txt +22 -0
  3. data/README.md +16 -0
  4. data/Rakefile +55 -0
  5. data/bin/oversip +182 -0
  6. data/ext/common/c_util.h +74 -0
  7. data/ext/common/ruby_c_util.h +88 -0
  8. data/ext/sip_parser/common_headers.h +209 -0
  9. data/ext/sip_parser/ext_help.h +18 -0
  10. data/ext/sip_parser/extconf.rb +3 -0
  11. data/ext/sip_parser/sip_parser.c +29649 -0
  12. data/ext/sip_parser/sip_parser.h +227 -0
  13. data/ext/sip_parser/sip_parser_ruby.c +1292 -0
  14. data/ext/stud/extconf.rb +27 -0
  15. data/ext/stud/stud.tar.gz +0 -0
  16. data/ext/stun/ext_help.h +16 -0
  17. data/ext/stun/extconf.rb +3 -0
  18. data/ext/stun/stun_ruby.c +391 -0
  19. data/ext/utils/ext_help.h +14 -0
  20. data/ext/utils/extconf.rb +3 -0
  21. data/ext/utils/haproxy_protocol.c +6163 -0
  22. data/ext/utils/haproxy_protocol.h +27 -0
  23. data/ext/utils/ip_utils.c +5952 -0
  24. data/ext/utils/ip_utils.h +61 -0
  25. data/ext/utils/outbound_utils.c +3227 -0
  26. data/ext/utils/outbound_utils.h +27 -0
  27. data/ext/utils/utils_ruby.c +384 -0
  28. data/ext/utils/utils_ruby.h +75 -0
  29. data/ext/websocket_framing_utils/ext_help.h +18 -0
  30. data/ext/websocket_framing_utils/extconf.rb +3 -0
  31. data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
  32. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  33. data/ext/websocket_http_parser/ext_help.h +18 -0
  34. data/ext/websocket_http_parser/extconf.rb +3 -0
  35. data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
  36. data/ext/websocket_http_parser/ws_http_parser.h +86 -0
  37. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  38. data/lib/oversip/config.rb +541 -0
  39. data/lib/oversip/config_validators.rb +126 -0
  40. data/lib/oversip/errors.rb +7 -0
  41. data/lib/oversip/fiber_pool.rb +56 -0
  42. data/lib/oversip/launcher.rb +507 -0
  43. data/lib/oversip/logger.rb +170 -0
  44. data/lib/oversip/master_process.rb +67 -0
  45. data/lib/oversip/posix_mq.rb +121 -0
  46. data/lib/oversip/proxies_config.rb +169 -0
  47. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  48. data/lib/oversip/sip/client_transaction.rb +587 -0
  49. data/lib/oversip/sip/constants.rb +87 -0
  50. data/lib/oversip/sip/grammar/name_addr.rb +27 -0
  51. data/lib/oversip/sip/grammar/uri.rb +116 -0
  52. data/lib/oversip/sip/launcher.rb +180 -0
  53. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  54. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
  55. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  56. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
  57. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
  58. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
  59. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  60. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
  61. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  62. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
  63. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
  64. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
  65. data/lib/oversip/sip/listeners/reactor.rb +39 -0
  66. data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
  67. data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
  68. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  69. data/lib/oversip/sip/listeners/tls_client.rb +117 -0
  70. data/lib/oversip/sip/listeners/tls_server.rb +70 -0
  71. data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
  72. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  73. data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
  74. data/lib/oversip/sip/listeners.rb +28 -0
  75. data/lib/oversip/sip/logic.rb +14 -0
  76. data/lib/oversip/sip/message.rb +168 -0
  77. data/lib/oversip/sip/message_processor.rb +202 -0
  78. data/lib/oversip/sip/modules/core.rb +200 -0
  79. data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
  80. data/lib/oversip/sip/modules/user_assertion.rb +123 -0
  81. data/lib/oversip/sip/proxy.rb +460 -0
  82. data/lib/oversip/sip/request.rb +128 -0
  83. data/lib/oversip/sip/response.rb +30 -0
  84. data/lib/oversip/sip/rfc3263.rb +646 -0
  85. data/lib/oversip/sip/server_transaction.rb +295 -0
  86. data/lib/oversip/sip/sip.rb +74 -0
  87. data/lib/oversip/sip/tags.rb +39 -0
  88. data/lib/oversip/sip/timers.rb +55 -0
  89. data/lib/oversip/sip/transport_manager.rb +129 -0
  90. data/lib/oversip/syslogger_process.rb +119 -0
  91. data/lib/oversip/tls.rb +179 -0
  92. data/lib/oversip/utils.rb +25 -0
  93. data/lib/oversip/version.rb +23 -0
  94. data/lib/oversip/websocket/constants.rb +56 -0
  95. data/lib/oversip/websocket/default_policy.rb +19 -0
  96. data/lib/oversip/websocket/http_request.rb +63 -0
  97. data/lib/oversip/websocket/launcher.rb +207 -0
  98. data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
  99. data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
  100. data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
  101. data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
  102. data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
  103. data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
  104. data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
  105. data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
  106. data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
  107. data/lib/oversip/websocket/listeners.rb +12 -0
  108. data/lib/oversip/websocket/ws_app.rb +75 -0
  109. data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
  110. data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
  111. data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
  112. data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
  113. data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
  114. data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
  115. data/lib/oversip/websocket/ws_apps.rb +9 -0
  116. data/lib/oversip/websocket/ws_framing.rb +597 -0
  117. data/lib/oversip.rb +59 -0
  118. data/test/oversip_test_helper.rb +20 -0
  119. data/test/test_http_parser.rb +73 -0
  120. data/test/test_sip_parser.rb +139 -0
  121. metadata +256 -0
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4TcpServer < TcpServer
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :tcp
7
+
8
+ LOG_ID = "WS TCP IPv4 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4TlsServer < TlsServer
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS IPv4 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4TlsTunnelServer < TlsTunnelServer
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS-Tunnel IPv4 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6TcpServer < TcpServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tcp
7
+
8
+ LOG_ID = "WS TCP IPv6 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6TlsServer < TlsServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS IPv6 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,15 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6TlsTunnelServer < TlsTunnelServer
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :tls
7
+
8
+ LOG_ID = "WS TLS-Tunnel IPv6 server"
9
+ def log_id
10
+ LOG_ID
11
+ end
12
+
13
+ end
14
+
15
+ end
@@ -0,0 +1,265 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class TcpServer < ::EM::Connection
4
+
5
+ include ::OverSIP::Logger
6
+ include ::OverSIP::WebSocket::DefaultPolicy
7
+ include ::OverSIP::WebSocket::Policy rescue nil # As it could not exist (i.e. the user deleted the file).
8
+
9
+ # Max size (bytes) of the buffered data when receiving message headers
10
+ # (avoid DoS attacks).
11
+ HEADERS_MAX_SIZE = 2048
12
+
13
+ WS_MAGIC_GUID_04 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".freeze
14
+ WS_VERSIONS = { 7=>true, 8=>true, 13=>true }
15
+ HDR_SUPPORTED_WEBSOCKET_VERSIONS = [ "X-Supported-WebSocket-Versions: #{WS_VERSIONS.keys.join(", ")}" ]
16
+
17
+
18
+ class << self
19
+ attr_accessor :ip_type, :transport
20
+ end
21
+
22
+ attr_accessor :ws_protocol, :ws_app_klass
23
+ attr_reader :connection_log_id, :remote_ip_type, :remote_ip, :remote_port
24
+
25
+
26
+ def initialize
27
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
28
+ @buffer = ::IO::Buffer.new
29
+ @state = :init
30
+ end
31
+
32
+
33
+ def post_connection
34
+ begin
35
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
36
+ rescue => e
37
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
38
+ close_connection
39
+ @state = :ignore
40
+ return
41
+ end
42
+ @connection_log_id = ::SecureRandom.hex(4)
43
+
44
+ log_system_info "connection opened from " << remote_desc
45
+ end
46
+
47
+
48
+ def remote_desc force=nil
49
+ if force
50
+ @remote_desc = case @remote_ip_type
51
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
52
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
53
+ end
54
+ else
55
+ @remote_desc ||= case self.class.ip_type
56
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
57
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
58
+ end
59
+ end
60
+ end
61
+
62
+
63
+ def unbind cause=nil
64
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
65
+
66
+ log_msg = "connection from #{remote_desc} "
67
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
68
+ log_msg << " (cause: #{cause.inspect})" if cause
69
+ log_system_debug log_msg if $oversip_debug
70
+
71
+ @ws_framing.tcp_closed if @ws_framing
72
+ end
73
+
74
+
75
+ def receive_data data
76
+ @state == :ignore and return
77
+ @buffer << data
78
+
79
+ while (case @state
80
+ when :init
81
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
82
+ @http_parser.reset
83
+ @http_parser_nbytes = 0
84
+ @bytes_remaining = 0
85
+ @state = :http_headers
86
+
87
+ when :http_headers
88
+ parse_http_headers
89
+
90
+ when :check_http_request
91
+ check_http_request
92
+
93
+ when :accept_ws_handshake
94
+ accept_ws_handshake
95
+
96
+ when :websocket_frames
97
+ return false if @buffer.size.zero?
98
+
99
+ @ws_framing.receive_data
100
+ false
101
+
102
+ when :ignore
103
+ false
104
+ end)
105
+ end # while
106
+
107
+ end
108
+
109
+
110
+ def parse_http_headers
111
+ return false if @buffer.empty?
112
+
113
+ # Parse the currently buffered data. If parsing fails @http_parser_nbytes gets nil value.
114
+ unless @http_parser_nbytes = @http_parser.execute(@http_request, @buffer.to_str, @http_parser_nbytes)
115
+ log_system_warn "parsing error: \"#{@http_parser.error}\""
116
+ close_connection_after_writing
117
+ @state = :ignore
118
+ return false
119
+ end
120
+
121
+ # Avoid flood attacks in TCP (very long headers).
122
+ if @http_parser_nbytes > HEADERS_MAX_SIZE
123
+ log_system_warn "DoS attack detected: headers size exceedes #{HEADERS_MAX_SIZE} bytes, closing connection with #{remote_desc}"
124
+ close_connection
125
+ @state = :ignore
126
+ return false
127
+ end
128
+
129
+ return false unless @http_parser.finished?
130
+
131
+ # Clear parsed data from the buffer.
132
+ @buffer.read(@http_parser_nbytes)
133
+
134
+ @http_request.connection = self
135
+ @http_request.transport = self.class.transport
136
+ @http_request.source_ip = @remote_ip
137
+ @http_request.source_port = @remote_port
138
+ @http_request.source_ip_type = @remote_ip_type ||= self.class.ip_type
139
+
140
+ @state = :check_http_request
141
+ true
142
+ end # parse_headers
143
+
144
+
145
+ def check_http_request
146
+
147
+ # HTTP method must be GET.
148
+ if @http_request.http_method != :GET
149
+ log_system_notice "rejecting HTTP #{@http_request.http_method} request => 405"
150
+ http_reject 405
151
+ return false
152
+ end
153
+
154
+ # "Sec-WebSocket-Version" must be 8.
155
+ unless WS_VERSIONS[@http_request.hdr_sec_websocket_version]
156
+ if @http_request.hdr_sec_websocket_version
157
+ log_system_notice "WebSocket version #{@http_request.hdr_sec_websocket_version} not implemented => 426"
158
+ else
159
+ log_system_notice "WebSocket version header not present => 426"
160
+ end
161
+ http_reject 426, nil, HDR_SUPPORTED_WEBSOCKET_VERSIONS
162
+ return false
163
+ end
164
+
165
+ # Connection header must include "upgrade".
166
+ unless @http_request.hdr_connection and @http_request.hdr_connection.include? "upgrade"
167
+ log_system_notice "Connection header must include \"upgrade\" => 400"
168
+ http_reject 400, "Connection header must include \"upgrade\""
169
+ return false
170
+ end
171
+
172
+ # "Upgrade: websocket" is required.
173
+ unless @http_request.hdr_upgrade == "websocket"
174
+ log_system_notice "Upgrade header must be \"websocket\" => 400"
175
+ http_reject 400, "Upgrade header must be \"websocket\""
176
+ return false
177
+ end
178
+
179
+ # Sec-WebSocket-Key is required.
180
+ unless @http_request.hdr_sec_websocket_key
181
+ log_system_notice "Sec-WebSocket-Key header not present => 400"
182
+ http_reject 400, "Sec-WebSocket-Key header not present"
183
+ return false
184
+ end
185
+
186
+ # Check Sec-WebSocket-Protocol.
187
+ if @http_request.hdr_sec_websocket_protocol
188
+ if @http_request.hdr_sec_websocket_protocol.include? @ws_protocol
189
+ @websocket_protocol_negotiated = true
190
+ else
191
+ log_system_notice "Sec-WebSocket-Protocol does not contain a supported protocol but #{@http_request.hdr_sec_websocket_protocol} => 501"
192
+ http_reject 501, "No Suitable WebSocket Protocol"
193
+ return false
194
+ end
195
+ end
196
+
197
+ # Check WebSocket policy.
198
+
199
+ unless check_hostport(@http_request.host, @http_request.port)
200
+ log_system_notice "host/port policy not satisfied (host=#{@http_request.host.inspect}, port=#{@http_request.port.inspect}) => 403"
201
+ http_reject 403, "request host/port not satisfied"
202
+ return false
203
+ end
204
+
205
+ unless check_origin(@http_request.hdr_origin)
206
+ log_system_notice "'Origin' policy not satisfied (origin=#{@http_request.hdr_origin.inspect}) => 403"
207
+ http_reject 403, "request 'Origin' not satisfied"
208
+ return false
209
+ end
210
+
211
+ unless check_request_uri(@http_request.uri_path, @http_request.uri_query)
212
+ log_system_notice "request URI path/query not satisfied (path=#{@http_request.uri_path.inspect}, query=#{@http_request.uri_query.inspect}) => 403"
213
+ http_reject 403, "request URI path/query not satisfied"
214
+ return false
215
+ end
216
+
217
+ @state = :accept_ws_handshake
218
+ true
219
+ end
220
+
221
+
222
+ def accept_ws_handshake
223
+ sec_websocket_accept = Digest::SHA1::base64digest @http_request.hdr_sec_websocket_key + WS_MAGIC_GUID_04
224
+
225
+ extra_headers = [
226
+ "Upgrade: websocket",
227
+ "Connection: Upgrade",
228
+ "Sec-WebSocket-Accept: #{sec_websocket_accept}"
229
+ ]
230
+
231
+ if @websocket_protocol_negotiated
232
+ extra_headers << "Sec-WebSocket-Protocol: #{@ws_protocol}"
233
+ end
234
+
235
+ if @websocket_extensions
236
+ extra_headers << "Sec-WebSocket-Extensions: #{@websocket_extensions.to_s}"
237
+ end
238
+
239
+ @http_request.reply 101, nil, extra_headers
240
+
241
+ # Set the WS framming layer and WS application layer.
242
+ @ws_framing = ::OverSIP::WebSocket::WsFraming.new(self, @buffer)
243
+ @ws_framing.ws_app = @ws_app_klass.new(self, @ws_framing)
244
+
245
+ @state = :websocket_frames
246
+ true
247
+ end
248
+
249
+
250
+ def http_reject status_code, reason_phrase=nil, extra_headers=nil
251
+ @http_request.reply(status_code, reason_phrase, extra_headers)
252
+ close_connection_after_writing
253
+ @state = :ignore
254
+ end
255
+
256
+
257
+ def ignore_incoming_data
258
+ @state = :ignore # The WS application needs to set the connection in :ignore state
259
+ # after sending a close frame to the client.
260
+ end
261
+
262
+ end # class TcpServer
263
+
264
+ end
265
+
@@ -0,0 +1,69 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class TlsServer < TcpServer
4
+
5
+ TLS_HANDSHAKE_MAX_TIME = 8
6
+
7
+
8
+ def post_init
9
+ @client_pems = []
10
+ @client_last_pem = false
11
+
12
+ start_tls({
13
+ :verify_peer => true,
14
+ :cert_chain_file => ::OverSIP.tls_public_cert,
15
+ :private_key_file => ::OverSIP.tls_private_cert
16
+ })
17
+
18
+ # If the remote client does never send us a TLS certificate
19
+ # after the TCP connection we would leak by storing more and
20
+ # more messages in @pending_messages array.
21
+ @timer_tls_handshake = ::EM::Timer.new(TLS_HANDSHAKE_MAX_TIME) do
22
+ unless @connected
23
+ log_system_notice "TLS handshake not performed within #{TLS_HANDSHAKE_MAX_TIME} seconds, closing the connection"
24
+ close_connection
25
+ end
26
+ end
27
+ end
28
+
29
+
30
+ def ssl_verify_peer pem
31
+ # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194.
32
+ return true if @client_last_pem == pem
33
+
34
+ @client_last_pem = pem
35
+ @client_pems << pem
36
+
37
+ log_system_debug "received certificate num #{@client_pems.size} from client" if $oversip_debug
38
+
39
+ # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true.
40
+ return true
41
+ end
42
+
43
+
44
+ def ssl_handshake_completed
45
+ log_system_info "TLS connection established from " << remote_desc
46
+
47
+ # TODO: What to do it falidation fails? always do validation?
48
+
49
+ validated, cert, tls_error, tls_error_string = ::OverSIP::TLS.validate @client_pems.pop, @client_pems
50
+ if validated
51
+ log_system_info "client provides a valid TLS certificate"
52
+ else
53
+ log_system_notice "client's TLS certificate validation failed (TLS error: #{tls_error.inspect}, description: #{tls_error_string.inspect})"
54
+ end
55
+
56
+ # @connected in TlsServer means "TLS connection" rather than
57
+ # just "TCP connection".
58
+ @connected = true
59
+ @timer_tls_handshake.cancel if @timer_tls_handshake
60
+ end
61
+
62
+
63
+ def unbind cause=nil
64
+ super
65
+ @timer_tls_handshake.cancel if @timer_tls_handshake
66
+ end
67
+
68
+ end
69
+ end
@@ -0,0 +1,100 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class TlsTunnelServer < TcpServer
4
+
5
+ def initialize
6
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
7
+ @buffer = ::IO::Buffer.new
8
+ @state = :init
9
+ end
10
+
11
+
12
+ def post_connection
13
+ begin
14
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
15
+ rescue => e
16
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
17
+ close_connection
18
+ @state = :ignore
19
+ return
20
+ end
21
+ @connection_log_id = ::SecureRandom.hex(4)
22
+
23
+ log_system_info "connection from the TLS tunnel " << remote_desc
24
+ end
25
+
26
+
27
+ def receive_data data
28
+ @state == :ignore and return
29
+ @buffer << data
30
+
31
+ while (case @state
32
+ when :init
33
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
34
+ @http_parser.reset
35
+ @http_parser_nbytes = 0
36
+ @bytes_remaining = 0
37
+ # If it's a TCP connection from the TLS proxy then parse the HAProxy Protocol line
38
+ # if it's not yet done.
39
+ unless @haproxy_protocol_parsed
40
+ @state = :haproxy_protocol
41
+ else
42
+ @state = :http_headers
43
+ end
44
+
45
+ when :haproxy_protocol
46
+ parse_haproxy_protocol
47
+
48
+ when :http_headers
49
+ parse_http_headers
50
+
51
+ when :check_http_request
52
+ check_http_request
53
+
54
+ when :accept_ws_handshake
55
+ accept_ws_handshake
56
+
57
+ when :websocket_frames
58
+ return false if @buffer.size.zero?
59
+
60
+ @ws_framing.receive_data
61
+ false
62
+
63
+ when :ignore
64
+ false
65
+ end)
66
+ end # while
67
+
68
+ end
69
+
70
+
71
+ def parse_haproxy_protocol
72
+ if (haproxy_protocol_data = ::OverSIP::Utils.parse_haproxy_protocol(@buffer.to_str))
73
+ @haproxy_protocol_parsed = true
74
+
75
+ # Update connection information.
76
+ @remote_ip_type = haproxy_protocol_data[1]
77
+ @remote_ip = haproxy_protocol_data[2]
78
+ @remote_port = haproxy_protocol_data[3]
79
+
80
+ # Update log information.
81
+ remote_desc true
82
+
83
+ # Remove the HAProxy Protocol line from the received data.
84
+ @buffer.read haproxy_protocol_data[0]
85
+
86
+ @state = :http_headers
87
+
88
+ # If parsing fails then the TLS proxy has sent us a wrong HAProxy Protocol line ¿?
89
+ else
90
+ log_system_error "HAProxy Protocol parsing error, closing connection"
91
+ close_connection_after_writing
92
+ @state = :ignore
93
+ return false
94
+ end
95
+ end
96
+
97
+ end
98
+
99
+ end
100
+
@@ -0,0 +1,12 @@
1
+ # OverSIP files
2
+
3
+ require "oversip/websocket/listeners/tcp_server"
4
+ require "oversip/websocket/listeners/tls_server"
5
+ require "oversip/websocket/listeners/tls_tunnel_server"
6
+
7
+ require "oversip/websocket/listeners/ipv4_tcp_server"
8
+ require "oversip/websocket/listeners/ipv6_tcp_server"
9
+ require "oversip/websocket/listeners/ipv4_tls_server"
10
+ require "oversip/websocket/listeners/ipv6_tls_server"
11
+ require "oversip/websocket/listeners/ipv4_tls_tunnel_server"
12
+ require "oversip/websocket/listeners/ipv6_tls_tunnel_server"
@@ -0,0 +1,75 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WsApp
4
+
5
+ include ::OverSIP::Logger
6
+
7
+
8
+ def self.class_init
9
+ @@max_message_size = ::OverSIP.configuration[:websocket][:max_ws_message_size]
10
+ @@ws_keepalive_interval = ::OverSIP.configuration[:websocket][:ws_keepalive_interval]
11
+ end
12
+
13
+
14
+ def initialize connection, ws_framing
15
+ @connection = connection
16
+ @ws_framing = ws_framing
17
+ @ws_message = ::IO::Buffer.new
18
+
19
+ # Mantain WebSocket keepalive.
20
+ @ws_framing.do_keep_alive @@ws_keepalive_interval if @@ws_keepalive_interval
21
+ end
22
+
23
+
24
+ def close_connection status=nil, reason=nil
25
+ @ws_framing.send_close_frame status, reason
26
+ end
27
+
28
+
29
+ def receive_payload_data payload_data
30
+ # payload_data is always Encoding::BINARY so also @ws_message.to_str.
31
+ @ws_message << payload_data
32
+
33
+ # Check max message size.
34
+ if @ws_message.size > @@max_message_size
35
+ close_connection 1009, "message too big"
36
+ return false
37
+ end
38
+ true
39
+ end
40
+
41
+
42
+ def message_done type
43
+ log_system_debug "received WS message: length=#{@ws_message.size}" if $oversip_debug
44
+
45
+ case type
46
+
47
+ when :text
48
+ ws_message = @ws_message.to_str.force_encoding ::Encoding::UTF_8
49
+ process_text_message ws_message
50
+
51
+ when :binary
52
+ process_binary_message @ws_message.to_str # As IO::Buffer#to_str always generates Encoding::BINARY.
53
+ end
54
+
55
+ @ws_message.clear
56
+ true
57
+ end
58
+
59
+
60
+ def tcp_closed
61
+ nil
62
+ end
63
+
64
+
65
+ # Methods to be overriden by child classes.
66
+ def process_text_message ws_message
67
+ end
68
+
69
+ def process_binary_message ws_message
70
+ end
71
+
72
+
73
+ end # WsApplication
74
+
75
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4WsSipApp < WsSipApp
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :ws
7
+ @connections = {}
8
+ @invite_server_transactions = {}
9
+ @non_invite_server_transactions = {}
10
+ @invite_client_transactions = {}
11
+ @non_invite_client_transactions = {}
12
+ @is_reliable_transport_listener = true
13
+
14
+ LOG_ID = "WS IPv4 SIP app"
15
+ def log_id
16
+ LOG_ID
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv4WssSipApp < WsSipApp
4
+
5
+ @ip_type = :ipv4
6
+ @transport = :wss
7
+ @connections = {}
8
+ @invite_server_transactions = {}
9
+ @non_invite_server_transactions = {}
10
+ @invite_client_transactions = {}
11
+ @non_invite_client_transactions = {}
12
+ @is_reliable_transport_listener = true
13
+
14
+ LOG_ID = "WSS IPv4 SIP app"
15
+ def log_id
16
+ LOG_ID
17
+ end
18
+
19
+ end
20
+
21
+ end
@@ -0,0 +1,21 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class IPv6WsSipApp < WsSipApp
4
+
5
+ @ip_type = :ipv6
6
+ @transport = :ws
7
+ @connections = {}
8
+ @invite_server_transactions = {}
9
+ @non_invite_server_transactions = {}
10
+ @invite_client_transactions = {}
11
+ @non_invite_client_transactions = {}
12
+ @is_reliable_transport_listener = true
13
+
14
+ LOG_ID = "WS IPv6 SIP app"
15
+ def log_id
16
+ LOG_ID
17
+ end
18
+
19
+ end
20
+
21
+ end