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,545 @@
|
|
|
1
|
+
module OverSIP::WebSocket
|
|
2
|
+
|
|
3
|
+
class WsFraming
|
|
4
|
+
|
|
5
|
+
include ::OverSIP::Logger
|
|
6
|
+
|
|
7
|
+
OPCODE = {
|
|
8
|
+
0 => :continuation,
|
|
9
|
+
1 => :text,
|
|
10
|
+
2 => :binary,
|
|
11
|
+
8 => :close,
|
|
12
|
+
9 => :ping,
|
|
13
|
+
10 => :pong
|
|
14
|
+
}
|
|
15
|
+
|
|
16
|
+
keepalive_ping_frame = "".encode ::Encoding::BINARY
|
|
17
|
+
keepalive_ping_frame << 137
|
|
18
|
+
keepalive_ping_frame << "keep-alive".bytesize
|
|
19
|
+
keepalive_ping_frame << "keep-alive".encode(::Encoding::BINARY)
|
|
20
|
+
KEEPALIVE_PING_FRAME = keepalive_ping_frame
|
|
21
|
+
|
|
22
|
+
|
|
23
|
+
def self.class_init
|
|
24
|
+
@@max_frame_size = ::OverSIP.configuration[:websocket][:max_ws_frame_size]
|
|
25
|
+
end
|
|
26
|
+
|
|
27
|
+
|
|
28
|
+
attr_writer :ws_app
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
LOG_ID = "WsFraming"
|
|
32
|
+
def log_id
|
|
33
|
+
LOG_ID
|
|
34
|
+
end
|
|
35
|
+
|
|
36
|
+
|
|
37
|
+
def initialize connection, buffer
|
|
38
|
+
@connection = connection
|
|
39
|
+
@buffer = buffer
|
|
40
|
+
@utf8_validator = ::OverSIP::WebSocket::FramingUtils::Utf8Validator.allocate
|
|
41
|
+
@state = :init
|
|
42
|
+
end
|
|
43
|
+
|
|
44
|
+
|
|
45
|
+
def do_keep_alive interval
|
|
46
|
+
@keep_alive_timer = ::EM::PeriodicTimer.new(interval) do
|
|
47
|
+
unless @connection.error? # Ensure it.
|
|
48
|
+
log_system_debug "sending keep-alive ping frame" if $oversip_debug
|
|
49
|
+
@connection.send_data KEEPALIVE_PING_FRAME
|
|
50
|
+
else
|
|
51
|
+
@keep_alive_timer.cancel
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
end
|
|
55
|
+
|
|
56
|
+
|
|
57
|
+
def receive_data
|
|
58
|
+
while (case @state
|
|
59
|
+
when :init
|
|
60
|
+
return false if @buffer.size < 2
|
|
61
|
+
|
|
62
|
+
byte1 = @buffer.read(1).getbyte(0)
|
|
63
|
+
byte2 = @buffer.read(1).getbyte(0)
|
|
64
|
+
|
|
65
|
+
# FIN is the bit 0.
|
|
66
|
+
@fin = (byte1 & 0b10000000) == 0b10000000
|
|
67
|
+
|
|
68
|
+
# RSV1-3 are bits 1-3.
|
|
69
|
+
@rsv1 = (byte1 & 0b01000000) == 0b01000000
|
|
70
|
+
@rsv2 = (byte1 & 0b00100000) == 0b00100000
|
|
71
|
+
@rsv3 = (byte1 & 0b00010000) == 0b00010000
|
|
72
|
+
|
|
73
|
+
if @rsv1 or @rsv2 or @rsv3
|
|
74
|
+
log_system_notice "frame has RSV bits set, clossing the connection"
|
|
75
|
+
@connection.close 1002, "RSV bit set not supported"
|
|
76
|
+
return false
|
|
77
|
+
end
|
|
78
|
+
|
|
79
|
+
# opcode are bits 4-7.
|
|
80
|
+
@opcode = byte1 & 0b00001111
|
|
81
|
+
unless (@sym_opcode = OPCODE[@opcode])
|
|
82
|
+
@connection.close 1002, "unknown opcode=#{@opcode}"
|
|
83
|
+
return false
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
# MASK is bit 8.
|
|
87
|
+
@mask = (byte2 & 0b10000000) == 0b10000000
|
|
88
|
+
unless @mask
|
|
89
|
+
@connection.close 1002, "MASK bit not set"
|
|
90
|
+
return false
|
|
91
|
+
end
|
|
92
|
+
|
|
93
|
+
# payload_len are bits 9-15.
|
|
94
|
+
length = byte2 & 0b01111111
|
|
95
|
+
|
|
96
|
+
case length
|
|
97
|
+
# Length defined by 8 bytes.
|
|
98
|
+
when 127
|
|
99
|
+
@state = :payload_length_8_bytes
|
|
100
|
+
# Length defined by 2 bytes.
|
|
101
|
+
when 126
|
|
102
|
+
@state = :payload_length_2_bytes
|
|
103
|
+
# Length defined by already received 7 bits.
|
|
104
|
+
else
|
|
105
|
+
@payload_length = length
|
|
106
|
+
@state = :masking_key
|
|
107
|
+
end
|
|
108
|
+
|
|
109
|
+
@payload = nil
|
|
110
|
+
true
|
|
111
|
+
|
|
112
|
+
when :payload_length_2_bytes
|
|
113
|
+
return false if @buffer.size < 2
|
|
114
|
+
|
|
115
|
+
# Get the payload length and remove first two bytes fro
|
|
116
|
+
# the buffer at the same time.
|
|
117
|
+
@payload_length = @buffer.read(2).unpack('n').first
|
|
118
|
+
|
|
119
|
+
@state = :masking_key
|
|
120
|
+
true
|
|
121
|
+
|
|
122
|
+
when :payload_length_8_bytes
|
|
123
|
+
return false if @buffer.size < 8
|
|
124
|
+
|
|
125
|
+
# Get the payload length.
|
|
126
|
+
# NOTE: Just take the last 4 bytes (4 GB frame is enough!!!),
|
|
127
|
+
# Check that first 4 bytes are 0000. If not then the frame is bigger
|
|
128
|
+
# than 4 GB and must be rejected!
|
|
129
|
+
|
|
130
|
+
if @buffer.read(4).unpack('N').first != 0
|
|
131
|
+
log_system_notice "frame size bigger than 4 GB, rejected"
|
|
132
|
+
@connection.close 1008
|
|
133
|
+
return false
|
|
134
|
+
end
|
|
135
|
+
|
|
136
|
+
@payload_length = @buffer.read(4).unpack('N').first
|
|
137
|
+
|
|
138
|
+
@state = :masking_key
|
|
139
|
+
true
|
|
140
|
+
|
|
141
|
+
when :masking_key
|
|
142
|
+
return false if @buffer.size < 4
|
|
143
|
+
|
|
144
|
+
# Get the masking key (4 bytes) and remove first 4 bytes
|
|
145
|
+
# from the buffer.
|
|
146
|
+
@masking_key = @buffer.read(4)
|
|
147
|
+
|
|
148
|
+
@state = :check_frame
|
|
149
|
+
true
|
|
150
|
+
|
|
151
|
+
when :check_frame
|
|
152
|
+
# All control frames MUST have a payload length of 125 bytes or
|
|
153
|
+
# less and MUST NOT be fragmented.
|
|
154
|
+
if control_frame? and @payload_length > 125
|
|
155
|
+
log_system_notice "received invalid control frame (payload_length > 125), sending close frame"
|
|
156
|
+
@connection.close 1002
|
|
157
|
+
return false
|
|
158
|
+
end
|
|
159
|
+
|
|
160
|
+
if control_frame? and not @fin
|
|
161
|
+
log_system_notice "received invalid control frame (FIN=0), sending close frame"
|
|
162
|
+
@connection.close 1002, "forbidden FIN=0 in control frame"
|
|
163
|
+
return false
|
|
164
|
+
end
|
|
165
|
+
|
|
166
|
+
# A continuation frame can only arrive if previously a text/binary frame
|
|
167
|
+
# arrived with FIN=0.
|
|
168
|
+
if continuation_frame? and not @msg_sym_opcode
|
|
169
|
+
log_system_notice "invalid continuation frame received (no previous unfinished message), sending close frame"
|
|
170
|
+
@connection.close 1002, "invalid continuation frame received"
|
|
171
|
+
return false
|
|
172
|
+
end
|
|
173
|
+
|
|
174
|
+
# If a previous frame had FIN=0 and opcode=text/binary, then it cannot arrive
|
|
175
|
+
# a new frame with opcode=text/binary.
|
|
176
|
+
if @msg_sym_opcode and text_or_binary_frame?
|
|
177
|
+
log_system_notice "invalid text/binary frame received (expecting a continuation frame), sending close frame"
|
|
178
|
+
@connection.close 1002, "expected a continuation frame"
|
|
179
|
+
return false
|
|
180
|
+
end
|
|
181
|
+
|
|
182
|
+
# Check max frame size.
|
|
183
|
+
if @payload_length > @@max_frame_size
|
|
184
|
+
@connection.close 1009, "frame too big"
|
|
185
|
+
return false
|
|
186
|
+
end
|
|
187
|
+
|
|
188
|
+
@state = :payload_data
|
|
189
|
+
true
|
|
190
|
+
|
|
191
|
+
when :payload_data
|
|
192
|
+
return false if @buffer.size < @payload_length
|
|
193
|
+
|
|
194
|
+
unless @payload_length.zero?
|
|
195
|
+
# NOTE: @payload will always be Encoding::BINARY
|
|
196
|
+
@payload = ::OverSIP::WebSocket::FramingUtils.unmask @buffer.read(@payload_length), @masking_key
|
|
197
|
+
end
|
|
198
|
+
# NOTE: @payload could be nil.
|
|
199
|
+
|
|
200
|
+
@state = :process_frame
|
|
201
|
+
true
|
|
202
|
+
|
|
203
|
+
when :process_frame
|
|
204
|
+
# Set it here as it could be changed later in this block.
|
|
205
|
+
@state = :init
|
|
206
|
+
|
|
207
|
+
case @sym_opcode
|
|
208
|
+
|
|
209
|
+
when :text
|
|
210
|
+
log_system_debug "received text frame: FIN=#{@fin}, RSV1-3=#{@rsv1}/#{@rsv2}/#{@rsv3}, payload_length=#{@payload_length}" if $oversip_debug
|
|
211
|
+
|
|
212
|
+
# Store the opcode of the first frame (if there is more frames for same message
|
|
213
|
+
# they will have opcode=continuation).
|
|
214
|
+
@msg_sym_opcode = @sym_opcode
|
|
215
|
+
|
|
216
|
+
# Reset the UTF8 validator.
|
|
217
|
+
@utf8_validator.reset
|
|
218
|
+
|
|
219
|
+
if @payload
|
|
220
|
+
if (valid_utf8 = @utf8_validator.validate(@payload)) == false
|
|
221
|
+
log_system_notice "received single text frame contains invalid UTF-8, closing the connection"
|
|
222
|
+
@connection.close 1007, "single text frame contains invalid UTF-8"
|
|
223
|
+
return false
|
|
224
|
+
end
|
|
225
|
+
|
|
226
|
+
if @fin and not valid_utf8
|
|
227
|
+
log_system_notice "received single text frame contains incomplete UTF-8, closing the connection"
|
|
228
|
+
@connection.close 1007, "single text frame contains incomplete UTF-8"
|
|
229
|
+
return false
|
|
230
|
+
end
|
|
231
|
+
|
|
232
|
+
# If @ws_app.receive_payload_data returns false it means that total
|
|
233
|
+
# message size is too big.
|
|
234
|
+
unless @ws_app.receive_payload_data @payload
|
|
235
|
+
@connection.close 1009, "message too big"
|
|
236
|
+
return false
|
|
237
|
+
end
|
|
238
|
+
end
|
|
239
|
+
|
|
240
|
+
# If message is finished tell it to the WS application.
|
|
241
|
+
if @fin
|
|
242
|
+
@ws_app.message_done @msg_sym_opcode
|
|
243
|
+
@msg_sym_opcode = nil
|
|
244
|
+
end
|
|
245
|
+
|
|
246
|
+
when :binary
|
|
247
|
+
log_system_debug "received binary frame: FIN=#{@fin}, RSV1-3=#{@rsv1}/#{@rsv2}/#{@rsv3}, payload_length=#{@payload_length}" if $oversip_debug
|
|
248
|
+
|
|
249
|
+
# Store the opcode of the first frame (if there is more frames for same message
|
|
250
|
+
# they will have opcode=continuation).
|
|
251
|
+
@msg_sym_opcode = @sym_opcode
|
|
252
|
+
|
|
253
|
+
if @payload
|
|
254
|
+
# If @ws_app.receive_payload_data returns false it means that total
|
|
255
|
+
# message size is too big.
|
|
256
|
+
unless @ws_app.receive_payload_data @payload
|
|
257
|
+
@connection.close 1009, "message too big"
|
|
258
|
+
return false
|
|
259
|
+
end
|
|
260
|
+
end
|
|
261
|
+
|
|
262
|
+
# If message is finished tell it to the WS application.
|
|
263
|
+
if @fin
|
|
264
|
+
@ws_app.message_done @msg_sym_opcode
|
|
265
|
+
@msg_sym_opcode = nil
|
|
266
|
+
end
|
|
267
|
+
|
|
268
|
+
when :continuation
|
|
269
|
+
log_system_debug "received continuation frame: FIN=#{@fin}, RSV1-3=#{@rsv1}/#{@rsv2}/#{@rsv3}, payload_length=#{@payload_length}" if $oversip_debug
|
|
270
|
+
|
|
271
|
+
if @payload
|
|
272
|
+
if @msg_sym_opcode == :text
|
|
273
|
+
if (valid_utf8 = @utf8_validator.validate(@payload)) == false
|
|
274
|
+
log_system_notice "received continuation text frame contains invalid UTF-8, closing the connection"
|
|
275
|
+
@connection.close 1007, "continuation text frame contains invalid UTF-8"
|
|
276
|
+
return false
|
|
277
|
+
end
|
|
278
|
+
|
|
279
|
+
if @fin and not valid_utf8
|
|
280
|
+
log_system_notice "received continuation final text frame contains incomplete UTF-8, closing the connection"
|
|
281
|
+
@connection.close 1007, "continuation final text frame contains incomplete UTF-8"
|
|
282
|
+
return false
|
|
283
|
+
end
|
|
284
|
+
end
|
|
285
|
+
|
|
286
|
+
return false unless @ws_app.receive_payload_data @payload
|
|
287
|
+
end
|
|
288
|
+
|
|
289
|
+
# If message is finished tell it to the WS application.
|
|
290
|
+
if @fin
|
|
291
|
+
@ws_app.message_done @msg_sym_opcode
|
|
292
|
+
@msg_sym_opcode = nil
|
|
293
|
+
end
|
|
294
|
+
|
|
295
|
+
when :close
|
|
296
|
+
if @payload_length >= 2
|
|
297
|
+
status = ""
|
|
298
|
+
status << @payload.getbyte(0) << @payload.getbyte(1)
|
|
299
|
+
status = status.unpack('n').first
|
|
300
|
+
if (reason = @payload[2..-1])
|
|
301
|
+
# Reset the UTF8 validator.
|
|
302
|
+
@utf8_validator.reset
|
|
303
|
+
|
|
304
|
+
# The UTF-8 validator returns:
|
|
305
|
+
# - true: Valid UTF-8 string.
|
|
306
|
+
# - nil: Valid but not terminated UTF-8 string.
|
|
307
|
+
# - false: Invalid UTF-8 string.
|
|
308
|
+
# So it must be true for the close frame reason.
|
|
309
|
+
unless @utf8_validator.validate(reason)
|
|
310
|
+
log_system_notice "received close frame with invalid UTF-8 data in the reason: status=#{status.inspect}"
|
|
311
|
+
@connection.close 1007, "close frame reason contains incomplete UTF-8"
|
|
312
|
+
return false
|
|
313
|
+
end
|
|
314
|
+
end
|
|
315
|
+
else
|
|
316
|
+
status = nil
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
case status
|
|
320
|
+
when 1002
|
|
321
|
+
log_system_notice "received close frame due to WS protocol error: status=1002, reason=#{reason.inspect}"
|
|
322
|
+
when 1003
|
|
323
|
+
log_system_notice "received close frame due to sent data type: status=1003, reason=#{reason.inspect}"
|
|
324
|
+
when 1007
|
|
325
|
+
log_system_notice "received close frame due to non valid UTF-8 data sent: status=1007, reason=#{reason.inspect}"
|
|
326
|
+
when 1009
|
|
327
|
+
log_system_notice "received close frame due to too big message sent: status=1009, reason=#{reason.inspect}"
|
|
328
|
+
when 1010
|
|
329
|
+
log_system_notice "received close frame due to extensions negotiation failure: status=1010, reason=#{reason.inspect}"
|
|
330
|
+
else
|
|
331
|
+
log_system_debug "received close frame: status=#{status.inspect}, reason=#{reason.inspect}" if $oversip_debug
|
|
332
|
+
end
|
|
333
|
+
|
|
334
|
+
@connection.client_closed = true
|
|
335
|
+
@connection.close nil, nil
|
|
336
|
+
return false
|
|
337
|
+
|
|
338
|
+
when :ping
|
|
339
|
+
log_system_debug "received ping frame: payload_length=#{@payload_length}" if $oversip_debug
|
|
340
|
+
send_pong_frame @payload
|
|
341
|
+
|
|
342
|
+
when :pong
|
|
343
|
+
log_system_debug "received pong frame: payload_length=#{@payload_length}" if $oversip_debug
|
|
344
|
+
|
|
345
|
+
end
|
|
346
|
+
|
|
347
|
+
true
|
|
348
|
+
end)
|
|
349
|
+
end # while
|
|
350
|
+
|
|
351
|
+
end # receive_data
|
|
352
|
+
|
|
353
|
+
|
|
354
|
+
def control_frame?
|
|
355
|
+
@opcode > 2
|
|
356
|
+
end
|
|
357
|
+
|
|
358
|
+
|
|
359
|
+
def text_or_binary_frame?
|
|
360
|
+
@opcode == 1 or @opcode == 2
|
|
361
|
+
end
|
|
362
|
+
|
|
363
|
+
|
|
364
|
+
def continuation_frame?
|
|
365
|
+
@opcode == 0
|
|
366
|
+
end
|
|
367
|
+
|
|
368
|
+
|
|
369
|
+
# NOTE: A WS message is always set in a single WS frame.
|
|
370
|
+
def send_text_frame message
|
|
371
|
+
log_system_debug "sending text frame: payload_length=#{message.bytesize}" if $oversip_debug
|
|
372
|
+
|
|
373
|
+
frame = "".encode ::Encoding::BINARY
|
|
374
|
+
|
|
375
|
+
# byte1 = OPCODE_TO_INT[:text] | 0b10000000 => 129
|
|
376
|
+
#
|
|
377
|
+
# - FIN bit set.
|
|
378
|
+
# - RSV1-3 bits not set.
|
|
379
|
+
# - opcode = 1
|
|
380
|
+
frame << 129
|
|
381
|
+
|
|
382
|
+
length = message.bytesize
|
|
383
|
+
if length <= 125
|
|
384
|
+
frame << length # since rsv4 is 0
|
|
385
|
+
elsif length < 65536 # write 2 byte length
|
|
386
|
+
frame << 126
|
|
387
|
+
frame << [length].pack('n')
|
|
388
|
+
else # write 8 byte length
|
|
389
|
+
frame << 127
|
|
390
|
+
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
|
391
|
+
end
|
|
392
|
+
|
|
393
|
+
if message.encoding == ::Encoding::BINARY
|
|
394
|
+
frame << message
|
|
395
|
+
else
|
|
396
|
+
frame << message.force_encoding(::Encoding::BINARY)
|
|
397
|
+
end
|
|
398
|
+
|
|
399
|
+
@connection.send_data frame
|
|
400
|
+
true
|
|
401
|
+
end
|
|
402
|
+
|
|
403
|
+
|
|
404
|
+
def send_binary_frame message
|
|
405
|
+
log_system_debug "sending binary frame: payload_length=#{message.bytesize}" if $oversip_debug
|
|
406
|
+
|
|
407
|
+
frame = "".encode ::Encoding::BINARY
|
|
408
|
+
|
|
409
|
+
# byte1 = OPCODE_TO_INT[:binary] | 0b10000000 => 130
|
|
410
|
+
#
|
|
411
|
+
# - FIN bit set.
|
|
412
|
+
# - RSV1-3 bits not set.
|
|
413
|
+
# - opcode = 2
|
|
414
|
+
frame << 130
|
|
415
|
+
|
|
416
|
+
length = message.bytesize
|
|
417
|
+
if length <= 125
|
|
418
|
+
frame << length # since rsv4 is 0
|
|
419
|
+
elsif length < 65536 # write 2 byte length
|
|
420
|
+
frame << 126
|
|
421
|
+
frame << [length].pack('n')
|
|
422
|
+
else # write 8 byte length
|
|
423
|
+
frame << 127
|
|
424
|
+
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
|
425
|
+
end
|
|
426
|
+
|
|
427
|
+
if message.encoding == ::Encoding::BINARY
|
|
428
|
+
frame << message
|
|
429
|
+
else
|
|
430
|
+
frame << message.force_encoding(::Encoding::BINARY)
|
|
431
|
+
end
|
|
432
|
+
|
|
433
|
+
@connection.send_data frame
|
|
434
|
+
true
|
|
435
|
+
end
|
|
436
|
+
|
|
437
|
+
|
|
438
|
+
def send_ping_frame data=nil
|
|
439
|
+
if data
|
|
440
|
+
log_system_debug "sending ping frame: payload_length=#{data.bytesize}" if $oversip_debug
|
|
441
|
+
else
|
|
442
|
+
log_system_debug "sending ping frame: payload_length=0" if $oversip_debug
|
|
443
|
+
end
|
|
444
|
+
|
|
445
|
+
frame = "".encode ::Encoding::BINARY
|
|
446
|
+
|
|
447
|
+
# byte1 = OPCODE_TO_INT[:ping] | 0b10000000 => 137
|
|
448
|
+
#
|
|
449
|
+
# - FIN bit set.
|
|
450
|
+
# - RSV1-3 bits not set.
|
|
451
|
+
# - opcode = 9
|
|
452
|
+
frame << 137
|
|
453
|
+
|
|
454
|
+
length = ( data ? data.bytesize : 0 )
|
|
455
|
+
frame << length
|
|
456
|
+
|
|
457
|
+
if data
|
|
458
|
+
if data.encoding == ::Encoding::BINARY
|
|
459
|
+
frame << data
|
|
460
|
+
else
|
|
461
|
+
frame << data.force_encoding(::Encoding::BINARY)
|
|
462
|
+
end
|
|
463
|
+
end
|
|
464
|
+
|
|
465
|
+
@connection.send_data frame
|
|
466
|
+
true
|
|
467
|
+
end
|
|
468
|
+
|
|
469
|
+
|
|
470
|
+
def send_pong_frame data=nil
|
|
471
|
+
if data
|
|
472
|
+
log_system_debug "sending pong frame: payload_length=#{data.bytesize}" if $oversip_debug
|
|
473
|
+
else
|
|
474
|
+
log_system_debug "sending pong frame: payload_length=0" if $oversip_debug
|
|
475
|
+
end
|
|
476
|
+
|
|
477
|
+
frame = "".encode ::Encoding::BINARY
|
|
478
|
+
|
|
479
|
+
# byte1 = OPCODE_TO_INT[:pong] | 0b10000000 => 138
|
|
480
|
+
#
|
|
481
|
+
# - FIN bit set.
|
|
482
|
+
# - RSV1-3 bits not set.
|
|
483
|
+
# - opcode = 10
|
|
484
|
+
frame << 138
|
|
485
|
+
|
|
486
|
+
length = ( data ? data.bytesize : 0 )
|
|
487
|
+
frame << length
|
|
488
|
+
|
|
489
|
+
if data
|
|
490
|
+
if data.encoding == ::Encoding::BINARY
|
|
491
|
+
frame << data
|
|
492
|
+
else
|
|
493
|
+
frame << data.force_encoding(::Encoding::BINARY)
|
|
494
|
+
end
|
|
495
|
+
end
|
|
496
|
+
|
|
497
|
+
@connection.send_data frame
|
|
498
|
+
true
|
|
499
|
+
end
|
|
500
|
+
|
|
501
|
+
|
|
502
|
+
def send_close_frame status=nil, reason=nil, in_reply_to_close=nil
|
|
503
|
+
@keep_alive_timer.cancel if @keep_alive_timer
|
|
504
|
+
|
|
505
|
+
unless in_reply_to_close
|
|
506
|
+
log_system_debug "sending close frame: status=#{status.inspect}, reason=#{reason.inspect}" if $oversip_debug
|
|
507
|
+
else
|
|
508
|
+
log_system_debug "sending reply close frame: status=#{status.inspect}, reason=#{reason.inspect}" if $oversip_debug
|
|
509
|
+
end
|
|
510
|
+
|
|
511
|
+
@buffer.clear
|
|
512
|
+
|
|
513
|
+
frame = "".encode ::Encoding::BINARY
|
|
514
|
+
|
|
515
|
+
# byte1 = OPCODE_TO_INT[:close] | 0b10000000 => 136
|
|
516
|
+
#
|
|
517
|
+
# - FIN bit set.
|
|
518
|
+
# - RSV1-3 bits not set.
|
|
519
|
+
# - opcode = 8
|
|
520
|
+
frame << 136
|
|
521
|
+
if status
|
|
522
|
+
length = ( reason ? 2 + reason.bytesize : 2 )
|
|
523
|
+
else
|
|
524
|
+
length = 0
|
|
525
|
+
end
|
|
526
|
+
|
|
527
|
+
frame << length # since rsv4 is 0
|
|
528
|
+
if status
|
|
529
|
+
frame << [status].pack('n')
|
|
530
|
+
if reason
|
|
531
|
+
if reason.encoding == ::Encoding::BINARY
|
|
532
|
+
frame << reason
|
|
533
|
+
else
|
|
534
|
+
frame << reason.force_encoding(::Encoding::BINARY)
|
|
535
|
+
end
|
|
536
|
+
end
|
|
537
|
+
end
|
|
538
|
+
|
|
539
|
+
@connection.send_data frame
|
|
540
|
+
true
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
end
|
|
544
|
+
|
|
545
|
+
end
|
|
@@ -0,0 +1,120 @@
|
|
|
1
|
+
module OverSIP::WebSocket
|
|
2
|
+
|
|
3
|
+
class WsSipApp
|
|
4
|
+
|
|
5
|
+
include ::OverSIP::Logger
|
|
6
|
+
include ::OverSIP::SIP::MessageProcessor
|
|
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
|
+
LOG_ID = "WsSipApp"
|
|
15
|
+
def log_id
|
|
16
|
+
LOG_ID
|
|
17
|
+
end
|
|
18
|
+
|
|
19
|
+
|
|
20
|
+
def initialize connection, ws_framing
|
|
21
|
+
@connection = connection
|
|
22
|
+
@ws_framing = ws_framing
|
|
23
|
+
@ws_message = ::IO::Buffer.new
|
|
24
|
+
|
|
25
|
+
# Mantain WebSocket keepalive.
|
|
26
|
+
@ws_framing.do_keep_alive @@ws_keepalive_interval if @@ws_keepalive_interval
|
|
27
|
+
|
|
28
|
+
# WebSocket is message boundary so we just need a SIP parser instance.
|
|
29
|
+
@@parser ||= ::OverSIP::SIP::MessageParser.new
|
|
30
|
+
@parser = @@parser
|
|
31
|
+
end
|
|
32
|
+
|
|
33
|
+
|
|
34
|
+
def receive_payload_data payload_data
|
|
35
|
+
# payload_data is always Encoding::BINARY so also @ws_message.to_str.
|
|
36
|
+
@ws_message << payload_data
|
|
37
|
+
|
|
38
|
+
# Check max message size.
|
|
39
|
+
return false if @ws_message.size > @@max_message_size
|
|
40
|
+
true
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def message_done type
|
|
45
|
+
log_system_debug "received WS message: type=#{type}, length=#{@ws_message.size}" if $oversip_debug
|
|
46
|
+
|
|
47
|
+
# Better to encode it as BINARY (to later extract the body).
|
|
48
|
+
process_sip_message @ws_message.to_str.force_encoding ::Encoding::BINARY
|
|
49
|
+
|
|
50
|
+
@ws_message.clear
|
|
51
|
+
true
|
|
52
|
+
end
|
|
53
|
+
|
|
54
|
+
|
|
55
|
+
def process_sip_message ws_message
|
|
56
|
+
# Just a single SIP message allowed per WS message.
|
|
57
|
+
@parser.reset
|
|
58
|
+
|
|
59
|
+
unless parser_nbytes = @parser.execute(ws_message, 0)
|
|
60
|
+
if wrong_message = @parser.parsed
|
|
61
|
+
log_system_warn "SIP parsing error for #{MSG_TYPE[wrong_message.class]}: \"#{@parser.error}\""
|
|
62
|
+
else
|
|
63
|
+
log_system_warn "SIP parsing error: \"#{@parser.error}\""
|
|
64
|
+
end
|
|
65
|
+
@connection.close 4000, "SIP message parsing error"
|
|
66
|
+
return
|
|
67
|
+
end
|
|
68
|
+
|
|
69
|
+
unless @parser.finished?
|
|
70
|
+
log_system_warn "SIP parsing error: message not completed"
|
|
71
|
+
|
|
72
|
+
@connection.close 4001, "SIP message incomplete"
|
|
73
|
+
return
|
|
74
|
+
end
|
|
75
|
+
|
|
76
|
+
# At this point we've got a SIP::Request, SIP::Response or :outbound_keepalive symbol.
|
|
77
|
+
@msg = @parser.parsed
|
|
78
|
+
|
|
79
|
+
# Received data is a SIP Outbound keealive (double CRLF). Reply with single CRLF.
|
|
80
|
+
if @msg == :outbound_keepalive
|
|
81
|
+
log_system_debug "Outbound keepalive received, replying single CRLF" if $oversip_debug
|
|
82
|
+
@ws_framing.send_text_frame(CRLF)
|
|
83
|
+
return
|
|
84
|
+
end
|
|
85
|
+
|
|
86
|
+
@parser.post_parsing
|
|
87
|
+
|
|
88
|
+
@msg.connection = @connection
|
|
89
|
+
@msg.transport = @connection.class.transport
|
|
90
|
+
@msg.source_ip = @connection.remote_ip
|
|
91
|
+
@msg.source_port = @connection.remote_port
|
|
92
|
+
@msg.source_ip_type = @connection.remote_ip_type
|
|
93
|
+
|
|
94
|
+
return unless valid_message? @parser
|
|
95
|
+
# TODO: Make it configurable:
|
|
96
|
+
#add_via_received_rport if @msg.request?
|
|
97
|
+
return unless check_via_branch
|
|
98
|
+
|
|
99
|
+
# Get the body.
|
|
100
|
+
if parser_nbytes != ws_message.bytesize
|
|
101
|
+
@msg.body = ws_message[parser_nbytes..-1].force_encoding(::Encoding::UTF_8)
|
|
102
|
+
|
|
103
|
+
if @msg.content_length and @msg.content_length != @msg.body.bytesize
|
|
104
|
+
log_system_warn "SIP message body size (#{@msg.body.bytesize}) does not match Content-Length (#{@msg.content_length.inspect}), ignoring message"
|
|
105
|
+
@connection.close 4002, "SIP message body size does not match Content-Length"
|
|
106
|
+
return
|
|
107
|
+
end
|
|
108
|
+
end
|
|
109
|
+
|
|
110
|
+
if @msg.request?
|
|
111
|
+
process_request
|
|
112
|
+
else
|
|
113
|
+
process_response
|
|
114
|
+
end
|
|
115
|
+
|
|
116
|
+
end
|
|
117
|
+
|
|
118
|
+
end
|
|
119
|
+
|
|
120
|
+
end
|