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.
Files changed (132) hide show
  1. checksums.yaml +7 -0
  2. data/AUTHORS +22 -0
  3. data/LICENSE +25 -0
  4. data/README.md +43 -0
  5. data/Rakefile +54 -0
  6. data/bin/oversip +184 -0
  7. data/etc/oversip.conf +274 -0
  8. data/etc/proxies.conf +145 -0
  9. data/etc/server.rb +315 -0
  10. data/etc/tls/ca/cacert.pem +3894 -0
  11. data/etc/tls/demo-tls.oversip.net.crt +17 -0
  12. data/etc/tls/demo-tls.oversip.net.key +15 -0
  13. data/etc/tls/upgrade-cacert.sh +12 -0
  14. data/etc/tls/utils/create-cert.rb +162 -0
  15. data/etc/tls/utils/get-sip-identities.rb +95 -0
  16. data/ext/common/c_util.h +74 -0
  17. data/ext/common/ruby_c_util.h +88 -0
  18. data/ext/sip_parser/common_headers.h +210 -0
  19. data/ext/sip_parser/ext_help.h +18 -0
  20. data/ext/sip_parser/extconf.rb +3 -0
  21. data/ext/sip_parser/sip_message_parser.c +29741 -0
  22. data/ext/sip_parser/sip_parser.h +250 -0
  23. data/ext/sip_parser/sip_parser_ruby.c +1370 -0
  24. data/ext/sip_parser/sip_uri_parser.c +39699 -0
  25. data/ext/stud/extconf.rb +43 -0
  26. data/ext/stun/ext_help.h +16 -0
  27. data/ext/stun/extconf.rb +3 -0
  28. data/ext/stun/stun_ruby.c +394 -0
  29. data/ext/utils/ext_help.h +14 -0
  30. data/ext/utils/extconf.rb +3 -0
  31. data/ext/utils/haproxy_protocol.c +6163 -0
  32. data/ext/utils/haproxy_protocol.h +27 -0
  33. data/ext/utils/ip_utils.c +5952 -0
  34. data/ext/utils/ip_utils.h +64 -0
  35. data/ext/utils/outbound_utils.c +3227 -0
  36. data/ext/utils/outbound_utils.h +27 -0
  37. data/ext/utils/utils_ruby.c +392 -0
  38. data/ext/utils/utils_ruby.h +76 -0
  39. data/ext/websocket_framing_utils/ext_help.h +18 -0
  40. data/ext/websocket_framing_utils/extconf.rb +3 -0
  41. data/ext/websocket_framing_utils/ws_framing_utils.h +47 -0
  42. data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
  43. data/ext/websocket_http_parser/ext_help.h +18 -0
  44. data/ext/websocket_http_parser/extconf.rb +3 -0
  45. data/ext/websocket_http_parser/ws_http_parser.c +1635 -0
  46. data/ext/websocket_http_parser/ws_http_parser.h +87 -0
  47. data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
  48. data/lib/oversip/config.rb +597 -0
  49. data/lib/oversip/config_validators.rb +126 -0
  50. data/lib/oversip/default_server.rb +52 -0
  51. data/lib/oversip/errors.rb +10 -0
  52. data/lib/oversip/fiber_pool.rb +56 -0
  53. data/lib/oversip/launcher.rb +635 -0
  54. data/lib/oversip/logger.rb +84 -0
  55. data/lib/oversip/modules/outbound_mangling.rb +56 -0
  56. data/lib/oversip/modules/user_assertion.rb +73 -0
  57. data/lib/oversip/proxies_config.rb +189 -0
  58. data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
  59. data/lib/oversip/sip/client.rb +428 -0
  60. data/lib/oversip/sip/client_transaction.rb +586 -0
  61. data/lib/oversip/sip/constants.rb +88 -0
  62. data/lib/oversip/sip/core.rb +217 -0
  63. data/lib/oversip/sip/launcher.rb +221 -0
  64. data/lib/oversip/sip/listeners/connection.rb +54 -0
  65. data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
  66. data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +22 -0
  67. data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
  68. data/lib/oversip/sip/listeners/ipv4_tls_server.rb +22 -0
  69. data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +22 -0
  70. data/lib/oversip/sip/listeners/ipv4_udp_server.rb +21 -0
  71. data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
  72. data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +22 -0
  73. data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
  74. data/lib/oversip/sip/listeners/ipv6_tls_server.rb +22 -0
  75. data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +22 -0
  76. data/lib/oversip/sip/listeners/ipv6_udp_server.rb +21 -0
  77. data/lib/oversip/sip/listeners/tcp_client.rb +97 -0
  78. data/lib/oversip/sip/listeners/tcp_connection.rb +202 -0
  79. data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
  80. data/lib/oversip/sip/listeners/tls_client.rb +125 -0
  81. data/lib/oversip/sip/listeners/tls_server.rb +88 -0
  82. data/lib/oversip/sip/listeners/tls_tunnel_connection.rb +89 -0
  83. data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
  84. data/lib/oversip/sip/listeners/udp_connection.rb +214 -0
  85. data/lib/oversip/sip/listeners.rb +24 -0
  86. data/lib/oversip/sip/message.rb +177 -0
  87. data/lib/oversip/sip/message_processor.rb +213 -0
  88. data/lib/oversip/sip/name_addr.rb +51 -0
  89. data/lib/oversip/sip/proxy.rb +324 -0
  90. data/lib/oversip/sip/request.rb +179 -0
  91. data/lib/oversip/sip/response.rb +37 -0
  92. data/lib/oversip/sip/rfc3263.rb +643 -0
  93. data/lib/oversip/sip/server_transaction.rb +295 -0
  94. data/lib/oversip/sip/sip.rb +76 -0
  95. data/lib/oversip/sip/tags.rb +39 -0
  96. data/lib/oversip/sip/timers.rb +55 -0
  97. data/lib/oversip/sip/transport_manager.rb +130 -0
  98. data/lib/oversip/sip/uac.rb +89 -0
  99. data/lib/oversip/sip/uac_request.rb +84 -0
  100. data/lib/oversip/sip/uri.rb +208 -0
  101. data/lib/oversip/syslog.rb +68 -0
  102. data/lib/oversip/system_callbacks.rb +45 -0
  103. data/lib/oversip/tls.rb +172 -0
  104. data/lib/oversip/utils.rb +30 -0
  105. data/lib/oversip/version.rb +21 -0
  106. data/lib/oversip/websocket/constants.rb +55 -0
  107. data/lib/oversip/websocket/http_request.rb +59 -0
  108. data/lib/oversip/websocket/launcher.rb +183 -0
  109. data/lib/oversip/websocket/listeners/connection.rb +51 -0
  110. data/lib/oversip/websocket/listeners/ipv4_ws_server.rb +22 -0
  111. data/lib/oversip/websocket/listeners/ipv4_wss_server.rb +22 -0
  112. data/lib/oversip/websocket/listeners/ipv4_wss_tunnel_server.rb +22 -0
  113. data/lib/oversip/websocket/listeners/ipv6_ws_server.rb +22 -0
  114. data/lib/oversip/websocket/listeners/ipv6_wss_server.rb +22 -0
  115. data/lib/oversip/websocket/listeners/ipv6_wss_tunnel_server.rb +22 -0
  116. data/lib/oversip/websocket/listeners/ws_server.rb +331 -0
  117. data/lib/oversip/websocket/listeners/wss_server.rb +88 -0
  118. data/lib/oversip/websocket/listeners/wss_tunnel_server.rb +133 -0
  119. data/lib/oversip/websocket/listeners.rb +13 -0
  120. data/lib/oversip/websocket/websocket.rb +13 -0
  121. data/lib/oversip/websocket/ws_framing.rb +545 -0
  122. data/lib/oversip/websocket/ws_sip_app.rb +120 -0
  123. data/lib/oversip.rb +127 -0
  124. data/test/oversip_test_helper.rb +19 -0
  125. data/test/test_http_parser.rb +73 -0
  126. data/test/test_name_addr.rb +27 -0
  127. data/test/test_name_addr_parser.rb +24 -0
  128. data/test/test_sip_message_parser.rb +168 -0
  129. data/test/test_sip_uri_parser.rb +56 -0
  130. data/test/test_uri.rb +68 -0
  131. data/thirdparty/stud/stud.tar.gz +0 -0
  132. metadata +334 -0
@@ -0,0 +1,331 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WsServer < Connection
4
+
5
+ # Max size (bytes) of the buffered data when receiving HTTP headers
6
+ # (avoid DoS attacks).
7
+ HEADERS_MAX_SIZE = 2048
8
+
9
+ WS_MAGIC_GUID_04 = "258EAFA5-E914-47DA-95CA-C5AB0DC85B11".freeze
10
+ WS_VERSIONS = { 7=>true, 8=>true, 13=>true }
11
+ HDR_SUPPORTED_WEBSOCKET_VERSIONS = [ "X-Supported-WebSocket-Versions: #{WS_VERSIONS.keys.join(", ")}" ]
12
+
13
+
14
+ attr_reader :outbound_flow_token
15
+ attr_writer :ws_established, :client_closed
16
+
17
+
18
+ def remote_ip_type
19
+ @remote_ip_type || self.class.ip_type
20
+ end
21
+
22
+ def remote_ip
23
+ @remote_ip
24
+ end
25
+
26
+ def remote_port
27
+ @remote_port
28
+ end
29
+
30
+ def transport
31
+ self.class.transport
32
+ end
33
+
34
+ def post_connection
35
+ begin
36
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
37
+ rescue => e
38
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
39
+ close_connection
40
+ @state = :ignore
41
+ return
42
+ end
43
+
44
+ @connection_id = ::OverSIP::SIP::TransportManager.add_connection self, self.class, self.class.ip_type, @remote_ip, @remote_port
45
+
46
+ # Create an Outbound (RFC 5626) flow token for this connection.
47
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
48
+
49
+ log_system_debug("connection opened from " << remote_desc) if $oversip_debug
50
+ end
51
+
52
+
53
+ def remote_desc force=nil
54
+ if force
55
+ @remote_desc = case @remote_ip_type
56
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
57
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
58
+ end
59
+ else
60
+ @remote_desc ||= case self.class.ip_type
61
+ when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
62
+ when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
63
+ end
64
+ end
65
+ end
66
+
67
+
68
+ def unbind cause=nil
69
+ @state = :ignore
70
+
71
+ # Remove the connection.
72
+ self.class.connections.delete @connection_id
73
+
74
+ # Remove the Outbound token flow.
75
+ ::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
76
+
77
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
78
+ @local_closed = false if @client_closed
79
+
80
+ if $oversip_debug
81
+ log_msg = "connection from #{remote_desc} "
82
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
83
+ log_msg << " (cause: #{cause.inspect})" if cause
84
+ log_system_debug log_msg
85
+ end unless $!
86
+
87
+ if @ws_established
88
+ # Run OverSIP::WebSocketEvents.on_disconnection
89
+ ::Fiber.new do
90
+ begin
91
+ ::OverSIP::WebSocketEvents.on_disconnection self, !@local_closed
92
+ rescue ::Exception => e
93
+ log_system_error "error calling OverSIP::WebSocketEvents.on_disconnection():"
94
+ log_system_error e
95
+ end
96
+ end.resume
97
+ end unless $!
98
+ end
99
+
100
+
101
+ def receive_data data
102
+ @state == :ignore and return
103
+ @buffer << data
104
+ @state == :waiting_for_on_client_tls_handshake and return
105
+ @state == :waiting_for_on_connection and return
106
+
107
+ process_received_data
108
+ end
109
+
110
+ def process_received_data
111
+ @state == :ignore and return
112
+
113
+ while (case @state
114
+ when :init
115
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
116
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
117
+ @http_parser_nbytes = 0
118
+ @bytes_remaining = 0
119
+ @state = :http_headers
120
+
121
+ when :http_headers
122
+ parse_http_headers
123
+
124
+ when :check_http_request
125
+ check_http_request
126
+
127
+ when :on_connection_callback
128
+ do_on_connection_callback
129
+ false
130
+
131
+ when :accept_ws_handshake
132
+ accept_ws_handshake
133
+
134
+ when :websocket
135
+ @ws_established = true
136
+ @ws_framing.receive_data
137
+ false
138
+
139
+ when :ignore
140
+ false
141
+ end)
142
+ end # while
143
+
144
+ end
145
+
146
+
147
+ def parse_http_headers
148
+ return false if @buffer.empty?
149
+
150
+ # Parse the currently buffered data. If parsing fails @http_parser_nbytes gets nil value.
151
+ unless @http_parser_nbytes = @http_parser.execute(@http_request, @buffer.to_str, @http_parser_nbytes)
152
+ log_system_warn "parsing error: \"#{@http_parser.error}\""
153
+ close_connection_after_writing
154
+ @state = :ignore
155
+ return false
156
+ end
157
+
158
+ # Avoid flood attacks in TCP (very long headers).
159
+ if @http_parser_nbytes > HEADERS_MAX_SIZE
160
+ log_system_warn "DoS attack detected: headers size exceedes #{HEADERS_MAX_SIZE} bytes, closing connection with #{remote_desc}"
161
+ close_connection
162
+ @state = :ignore
163
+ return false
164
+ end
165
+
166
+ return false unless @http_parser.finished?
167
+
168
+ # Clear parsed data from the buffer.
169
+ @buffer.read(@http_parser_nbytes)
170
+
171
+ @http_request.connection = self
172
+
173
+ @state = :check_http_request
174
+ true
175
+ end # parse_headers
176
+
177
+
178
+ def check_http_request
179
+ # Check OverSIP status.
180
+ unless ::OverSIP.status == :running
181
+ case ::OverSIP.status
182
+ when :loading
183
+ http_reject 500, "Server Still Loading", [ "Retry-After: 5" ]
184
+ when :terminating
185
+ http_reject 500, "Server is Being Stopped"
186
+ end
187
+ return false
188
+ end
189
+
190
+ # HTTP method must be GET.
191
+ if @http_request.http_method != :GET
192
+ log_system_notice "rejecting HTTP #{@http_request.http_method} request => 405"
193
+ http_reject 405
194
+ return false
195
+ end
196
+
197
+ # "Sec-WebSocket-Version" must be 8.
198
+ unless WS_VERSIONS[@http_request.hdr_sec_websocket_version]
199
+ if @http_request.hdr_sec_websocket_version
200
+ log_system_notice "WebSocket version #{@http_request.hdr_sec_websocket_version} not implemented => 426"
201
+ else
202
+ log_system_notice "WebSocket version header not present => 426"
203
+ end
204
+ http_reject 426, nil, HDR_SUPPORTED_WEBSOCKET_VERSIONS
205
+ return false
206
+ end
207
+
208
+ # Connection header must include "upgrade".
209
+ unless @http_request.hdr_connection and @http_request.hdr_connection.include? "upgrade"
210
+ log_system_notice "Connection header must include \"upgrade\" => 400"
211
+ http_reject 400, "Connection header must include \"upgrade\""
212
+ return false
213
+ end
214
+
215
+ # "Upgrade: websocket" is required.
216
+ unless @http_request.hdr_upgrade == "websocket"
217
+ log_system_notice "Upgrade header must be \"websocket\" => 400"
218
+ http_reject 400, "Upgrade header must be \"websocket\""
219
+ return false
220
+ end
221
+
222
+ # Sec-WebSocket-Key is required.
223
+ unless @http_request.hdr_sec_websocket_key
224
+ log_system_notice "Sec-WebSocket-Key header not present => 400"
225
+ http_reject 400, "Sec-WebSocket-Key header not present"
226
+ return false
227
+ end
228
+
229
+ # Check Sec-WebSocket-Protocol.
230
+ if @http_request.hdr_sec_websocket_protocol
231
+ if @http_request.hdr_sec_websocket_protocol.include? WS_SIP_PROTOCOL
232
+ @websocket_protocol_negotiated = true
233
+ else
234
+ log_system_notice "Sec-WebSocket-Protocol does not contain a supported protocol but #{@http_request.hdr_sec_websocket_protocol} => 501"
235
+ http_reject 501, "No Suitable WebSocket Protocol"
236
+ return false
237
+ end
238
+ end
239
+
240
+ @state = :on_connection_callback
241
+ true
242
+ end
243
+
244
+
245
+ def do_on_connection_callback
246
+ # Set the state to :waiting_for_on_connection so data received before
247
+ # user callback validation is just stored.
248
+ @state = :waiting_for_on_connection
249
+
250
+ # Run OverSIP::WebSocketEvents.on_connection.
251
+ ::Fiber.new do
252
+ begin
253
+ log_system_debug "running OverSIP::WebSocketEvents.on_connection()..." if $oversip_debug
254
+ ::OverSIP::WebSocketEvents.on_connection self, @http_request
255
+ # If the user of the peer has not closed the connection then continue.
256
+ unless @local_closed or error?
257
+ @state = :accept_ws_handshake
258
+ # Call process_received_data() to process possible data received in the meanwhile.
259
+ process_received_data
260
+ else
261
+ log_system_debug "connection closed during OverSIP::WebSocketEvents.on_connection(), aborting" if $oversip_debug
262
+ end
263
+
264
+ rescue ::Exception => e
265
+ log_system_error "error calling OverSIP::WebSocketEvents.on_connection() => 500:"
266
+ log_system_error e
267
+ http_reject 500
268
+ end
269
+ end.resume
270
+ end
271
+
272
+
273
+ def accept_ws_handshake
274
+ sec_websocket_accept = Digest::SHA1::base64digest @http_request.hdr_sec_websocket_key + WS_MAGIC_GUID_04
275
+
276
+ extra_headers = [
277
+ "Upgrade: websocket",
278
+ "Connection: Upgrade",
279
+ "Sec-WebSocket-Accept: #{sec_websocket_accept}"
280
+ ]
281
+
282
+ if @websocket_protocol_negotiated
283
+ extra_headers << "Sec-WebSocket-Protocol: #{WS_SIP_PROTOCOL}"
284
+ end
285
+
286
+ if @websocket_extensions
287
+ extra_headers << "Sec-WebSocket-Extensions: #{@websocket_extensions.to_s}"
288
+ end
289
+
290
+ @http_request.reply 101, nil, extra_headers
291
+
292
+ # Set the WS framing layer and WS application layer.
293
+ @ws_framing = ::OverSIP::WebSocket::WsFraming.new self, @buffer
294
+ ws_sip_app = ::OverSIP::WebSocket::WsSipApp.new self, @ws_framing
295
+ @ws_framing.ws_app = ws_sip_app
296
+
297
+ @state = :websocket
298
+ true
299
+ end
300
+
301
+
302
+ def http_reject status_code=403, reason_phrase=nil, extra_headers=nil
303
+ @http_request.reply(status_code, reason_phrase, extra_headers)
304
+ close_connection_after_writing
305
+ @state = :ignore
306
+ end
307
+
308
+
309
+ # Parameters ip and port are just included because they are needed in UDP, so the API remains equal.
310
+ def send_sip_msg msg, ip=nil, port=nil
311
+ if self.error?
312
+ log_system_notice "SIP message could not be sent, connection is closed"
313
+ return false
314
+ end
315
+
316
+ # If the SIP message is fully valid UTF-8 send a WS text frame.
317
+ if msg.force_encoding(::Encoding::UTF_8).valid_encoding?
318
+ @ws_framing.send_text_frame msg
319
+
320
+ # If not, send a WS binary frame.
321
+ else
322
+ @ws_framing.send_binary_frame msg
323
+ end
324
+
325
+ true
326
+ end
327
+
328
+ end
329
+
330
+ end
331
+
@@ -0,0 +1,88 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WssServer < WsServer
4
+
5
+ TLS_HANDSHAKE_MAX_TIME = 4
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
+ :ssl_version => %w(sslv2) # USE SSL instead of TLS. TODO: yes?
17
+ })
18
+
19
+ # If the remote client does never send us a TLS certificate
20
+ # after the TCP connection we would leak by storing more and
21
+ # more messages in @pending_messages array.
22
+ @timer_tls_handshake = ::EM::Timer.new(TLS_HANDSHAKE_MAX_TIME) do
23
+ unless @connected
24
+ log_system_notice "TLS handshake not performed within #{TLS_HANDSHAKE_MAX_TIME} seconds, closing the connection"
25
+ close_connection
26
+ end
27
+ end
28
+ end
29
+
30
+
31
+ def ssl_verify_peer pem
32
+ # TODO: Dirty workaround for bug https://github.com/eventmachine/eventmachine/issues/194.
33
+ return true if @client_last_pem == pem
34
+
35
+ @client_last_pem = pem
36
+ @client_pems << pem
37
+
38
+ log_system_debug "received certificate num #{@client_pems.size} from client" if $oversip_debug
39
+
40
+ # Validation must be done in ssl_handshake_completed after receiving all the certs, so return true.
41
+ return true
42
+ end
43
+
44
+
45
+ def ssl_handshake_completed
46
+ log_system_debug ("TLS connection established from " << remote_desc) if $oversip_debug
47
+
48
+ # @connected in WssServer means "TLS connection" rather than
49
+ # just "TCP connection".
50
+ @connected = true
51
+ @timer_tls_handshake.cancel if @timer_tls_handshake
52
+
53
+ if ::OverSIP::WebSocket.callback_on_client_tls_handshake
54
+ # Set the state to :waiting_for_on_client_tls_handshake so data received after TLS handshake but before
55
+ # user callback validation is just stored.
56
+ @state = :waiting_for_on_client_tls_handshake
57
+
58
+ # Run OverSIP::WebSocketEvents.on_client_tls_handshake.
59
+ ::Fiber.new do
60
+ begin
61
+ log_system_debug "running OverSIP::SipWebSocketEvents.on_client_tls_handshake()..." if $oversip_debug
62
+ ::OverSIP::WebSocketEvents.on_client_tls_handshake self, @client_pems
63
+ # If the user of the peer has not closed the connection then continue.
64
+ unless @local_closed or error?
65
+ @state = :init
66
+ # Call process_received_data() to process possible data received in the meanwhile.
67
+ process_received_data
68
+ else
69
+ log_system_debug "connection closed during OverSIP::SipWebSocketEvents.on_client_tls_handshake(), aborting" if $oversip_debug
70
+ end
71
+
72
+ rescue ::Exception => e
73
+ log_system_error "error calling OverSIP::WebSocketEvents.on_client_tls_handshake():"
74
+ log_system_error e
75
+ close_connection
76
+ end
77
+ end.resume
78
+ end
79
+ end
80
+
81
+
82
+ def unbind cause=nil
83
+ @timer_tls_handshake.cancel if @timer_tls_handshake
84
+ super
85
+ end
86
+
87
+ end
88
+ end
@@ -0,0 +1,133 @@
1
+ module OverSIP::WebSocket
2
+
3
+ class WssTunnelServer < WsServer
4
+
5
+ def post_connection
6
+ begin
7
+ # Temporal @remote_ip and @remote_port until the HAProxy protocol line is parsed.
8
+ @remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
9
+ rescue => e
10
+ log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
11
+ close_connection
12
+ @state = :ignore
13
+ return
14
+ end
15
+
16
+ # Create an Outbound (RFC 5626) flow token for this connection.
17
+ @outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
18
+
19
+ log_system_debug ("connection from the TLS tunnel " << remote_desc) if $oversip_debug
20
+ end
21
+
22
+
23
+ def unbind cause=nil
24
+ @state = :ignore
25
+
26
+ # Remove the connection.
27
+ self.class.connections.delete @connection_id if @connection_id
28
+
29
+ # Remove the Outbound token flow.
30
+ ::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
31
+
32
+ @local_closed = true if cause == ::Errno::ETIMEDOUT
33
+ @local_closed = false if @client_closed
34
+
35
+ if $oversip_debug
36
+ log_msg = "connection from the TLS tunnel #{remote_desc} "
37
+ log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
38
+ log_msg << " (cause: #{cause.inspect})" if cause
39
+ log_system_debug log_msg
40
+ end unless $!
41
+
42
+ if @ws_established
43
+ # Run OverSIP::WebSocketEvents.on_disconnection
44
+ ::Fiber.new do
45
+ begin
46
+ ::OverSIP::WebSocketEvents.on_disconnection self, !@local_closed
47
+ rescue ::Exception => e
48
+ log_system_error "error calling OverSIP::WebSocketEvents.on_disconnection():"
49
+ log_system_error e
50
+ end
51
+ end.resume
52
+ end unless $!
53
+ end
54
+
55
+
56
+ def process_received_data
57
+ @state == :ignore and return
58
+
59
+ while (case @state
60
+ when :init
61
+ @http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
62
+ @http_request = ::OverSIP::WebSocket::HttpRequest.new
63
+ @http_parser.reset
64
+ @http_parser_nbytes = 0
65
+ @bytes_remaining = 0
66
+ # If it's a TCP connection from the TLS proxy then parse the HAProxy Protocol line
67
+ # if it's not yet done.
68
+ unless @haproxy_protocol_parsed
69
+ @state = :haproxy_protocol
70
+ else
71
+ @state = :http_headers
72
+ end
73
+
74
+ when :haproxy_protocol
75
+ parse_haproxy_protocol
76
+
77
+ when :http_headers
78
+ parse_http_headers
79
+
80
+ when :check_http_request
81
+ check_http_request
82
+
83
+ when :on_connection_callback
84
+ do_on_connection_callback
85
+ false
86
+
87
+ when :accept_ws_handshake
88
+ accept_ws_handshake
89
+
90
+ when :websocket
91
+ @ws_established = true
92
+ return false if @buffer.size.zero?
93
+ @ws_framing.receive_data
94
+ false
95
+
96
+ when :ignore
97
+ false
98
+ end)
99
+ end # while
100
+
101
+ end
102
+
103
+
104
+ def parse_haproxy_protocol
105
+ if (haproxy_protocol_data = ::OverSIP::Utils.parse_haproxy_protocol(@buffer.to_str))
106
+ @haproxy_protocol_parsed = true
107
+
108
+ # Update connection information.
109
+ @remote_ip_type = haproxy_protocol_data[1]
110
+ @remote_ip = haproxy_protocol_data[2]
111
+ @remote_port = haproxy_protocol_data[3]
112
+
113
+ # Update log information.
114
+ remote_desc true
115
+
116
+ # Remove the HAProxy Protocol line from the received data.
117
+ @buffer.read haproxy_protocol_data[0]
118
+
119
+ @state = :http_headers
120
+
121
+ # If parsing fails then the TLS proxy has sent us a wrong HAProxy Protocol line ¿?
122
+ else
123
+ log_system_error "HAProxy Protocol parsing error, closing connection"
124
+ close_connection_after_writing
125
+ @state = :ignore
126
+ return false
127
+ end
128
+ end
129
+
130
+ end
131
+
132
+ end
133
+
@@ -0,0 +1,13 @@
1
+ # OverSIP files
2
+
3
+ require "oversip/websocket/listeners/connection"
4
+ require "oversip/websocket/listeners/ws_server"
5
+ require "oversip/websocket/listeners/wss_server"
6
+ require "oversip/websocket/listeners/wss_tunnel_server"
7
+
8
+ require "oversip/websocket/listeners/ipv4_ws_server"
9
+ require "oversip/websocket/listeners/ipv6_ws_server"
10
+ require "oversip/websocket/listeners/ipv4_wss_server"
11
+ require "oversip/websocket/listeners/ipv6_wss_server"
12
+ require "oversip/websocket/listeners/ipv4_wss_tunnel_server"
13
+ require "oversip/websocket/listeners/ipv6_wss_tunnel_server"
@@ -0,0 +1,13 @@
1
+ module OverSIP::WebSocket
2
+
3
+ def self.module_init
4
+ conf = ::OverSIP.configuration
5
+
6
+ @callback_on_client_tls_handshake = conf[:websocket][:callback_on_client_tls_handshake]
7
+ end
8
+
9
+ def self.callback_on_client_tls_handshake
10
+ @callback_on_client_tls_handshake
11
+ end
12
+
13
+ end