oversip 0.9.0
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- data/AUTHORS.txt +11 -0
- data/LICENSE.txt +22 -0
- data/README.md +16 -0
- data/Rakefile +55 -0
- data/bin/oversip +182 -0
- data/ext/common/c_util.h +74 -0
- data/ext/common/ruby_c_util.h +88 -0
- data/ext/sip_parser/common_headers.h +209 -0
- data/ext/sip_parser/ext_help.h +18 -0
- data/ext/sip_parser/extconf.rb +3 -0
- data/ext/sip_parser/sip_parser.c +29649 -0
- data/ext/sip_parser/sip_parser.h +227 -0
- data/ext/sip_parser/sip_parser_ruby.c +1292 -0
- data/ext/stud/extconf.rb +27 -0
- data/ext/stud/stud.tar.gz +0 -0
- data/ext/stun/ext_help.h +16 -0
- data/ext/stun/extconf.rb +3 -0
- data/ext/stun/stun_ruby.c +391 -0
- data/ext/utils/ext_help.h +14 -0
- data/ext/utils/extconf.rb +3 -0
- data/ext/utils/haproxy_protocol.c +6163 -0
- data/ext/utils/haproxy_protocol.h +27 -0
- data/ext/utils/ip_utils.c +5952 -0
- data/ext/utils/ip_utils.h +61 -0
- data/ext/utils/outbound_utils.c +3227 -0
- data/ext/utils/outbound_utils.h +27 -0
- data/ext/utils/utils_ruby.c +384 -0
- data/ext/utils/utils_ruby.h +75 -0
- data/ext/websocket_framing_utils/ext_help.h +18 -0
- data/ext/websocket_framing_utils/extconf.rb +3 -0
- data/ext/websocket_framing_utils/ws_framing_utils.h +46 -0
- data/ext/websocket_framing_utils/ws_framing_utils_ruby.c +135 -0
- data/ext/websocket_http_parser/ext_help.h +18 -0
- data/ext/websocket_http_parser/extconf.rb +3 -0
- data/ext/websocket_http_parser/ws_http_parser.c +2598 -0
- data/ext/websocket_http_parser/ws_http_parser.h +86 -0
- data/ext/websocket_http_parser/ws_http_parser_ruby.c +630 -0
- data/lib/oversip/config.rb +541 -0
- data/lib/oversip/config_validators.rb +126 -0
- data/lib/oversip/errors.rb +7 -0
- data/lib/oversip/fiber_pool.rb +56 -0
- data/lib/oversip/launcher.rb +507 -0
- data/lib/oversip/logger.rb +170 -0
- data/lib/oversip/master_process.rb +67 -0
- data/lib/oversip/posix_mq.rb +121 -0
- data/lib/oversip/proxies_config.rb +169 -0
- data/lib/oversip/ruby_ext/eventmachine.rb +38 -0
- data/lib/oversip/sip/client_transaction.rb +587 -0
- data/lib/oversip/sip/constants.rb +87 -0
- data/lib/oversip/sip/grammar/name_addr.rb +27 -0
- data/lib/oversip/sip/grammar/uri.rb +116 -0
- data/lib/oversip/sip/launcher.rb +180 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv4_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tcp_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_client.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_tls_tunnel_server.rb +21 -0
- data/lib/oversip/sip/listeners/ipv6_udp_server.rb +20 -0
- data/lib/oversip/sip/listeners/reactor.rb +39 -0
- data/lib/oversip/sip/listeners/tcp_client.rb +73 -0
- data/lib/oversip/sip/listeners/tcp_reactor.rb +185 -0
- data/lib/oversip/sip/listeners/tcp_server.rb +71 -0
- data/lib/oversip/sip/listeners/tls_client.rb +117 -0
- data/lib/oversip/sip/listeners/tls_server.rb +70 -0
- data/lib/oversip/sip/listeners/tls_tunnel_reactor.rb +113 -0
- data/lib/oversip/sip/listeners/tls_tunnel_server.rb +61 -0
- data/lib/oversip/sip/listeners/udp_reactor.rb +213 -0
- data/lib/oversip/sip/listeners.rb +28 -0
- data/lib/oversip/sip/logic.rb +14 -0
- data/lib/oversip/sip/message.rb +168 -0
- data/lib/oversip/sip/message_processor.rb +202 -0
- data/lib/oversip/sip/modules/core.rb +200 -0
- data/lib/oversip/sip/modules/registrar_without_path.rb +75 -0
- data/lib/oversip/sip/modules/user_assertion.rb +123 -0
- data/lib/oversip/sip/proxy.rb +460 -0
- data/lib/oversip/sip/request.rb +128 -0
- data/lib/oversip/sip/response.rb +30 -0
- data/lib/oversip/sip/rfc3263.rb +646 -0
- data/lib/oversip/sip/server_transaction.rb +295 -0
- data/lib/oversip/sip/sip.rb +74 -0
- data/lib/oversip/sip/tags.rb +39 -0
- data/lib/oversip/sip/timers.rb +55 -0
- data/lib/oversip/sip/transport_manager.rb +129 -0
- data/lib/oversip/syslogger_process.rb +119 -0
- data/lib/oversip/tls.rb +179 -0
- data/lib/oversip/utils.rb +25 -0
- data/lib/oversip/version.rb +23 -0
- data/lib/oversip/websocket/constants.rb +56 -0
- data/lib/oversip/websocket/default_policy.rb +19 -0
- data/lib/oversip/websocket/http_request.rb +63 -0
- data/lib/oversip/websocket/launcher.rb +207 -0
- data/lib/oversip/websocket/listeners/ipv4_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv4_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tcp_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_server.rb +15 -0
- data/lib/oversip/websocket/listeners/ipv6_tls_tunnel_server.rb +15 -0
- data/lib/oversip/websocket/listeners/tcp_server.rb +265 -0
- data/lib/oversip/websocket/listeners/tls_server.rb +69 -0
- data/lib/oversip/websocket/listeners/tls_tunnel_server.rb +100 -0
- data/lib/oversip/websocket/listeners.rb +12 -0
- data/lib/oversip/websocket/ws_app.rb +75 -0
- data/lib/oversip/websocket/ws_apps/ipv4_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv4_wss_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_ws_sip_app.rb +21 -0
- data/lib/oversip/websocket/ws_apps/ipv6_wss_sip_app.rb +22 -0
- data/lib/oversip/websocket/ws_apps/ws_autobahn_app.rb +23 -0
- data/lib/oversip/websocket/ws_apps/ws_sip_app.rb +156 -0
- data/lib/oversip/websocket/ws_apps.rb +9 -0
- data/lib/oversip/websocket/ws_framing.rb +597 -0
- data/lib/oversip.rb +59 -0
- data/test/oversip_test_helper.rb +20 -0
- data/test/test_http_parser.rb +73 -0
- data/test/test_sip_parser.rb +139 -0
- metadata +256 -0
|
@@ -0,0 +1,597 @@
|
|
|
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
|
+
attr_writer :ws_app
|
|
24
|
+
|
|
25
|
+
|
|
26
|
+
def self.class_init
|
|
27
|
+
@@max_frame_size = ::OverSIP.configuration[:websocket][:max_ws_frame_size]
|
|
28
|
+
end
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
def log_id
|
|
32
|
+
@log_id ||= "WsFramming #{@connection.connection_log_id}"
|
|
33
|
+
end
|
|
34
|
+
|
|
35
|
+
|
|
36
|
+
def initialize connection, buffer
|
|
37
|
+
@connection = connection
|
|
38
|
+
@buffer = buffer
|
|
39
|
+
@utf8_validator = ::OverSIP::WebSocket::FramingUtils::Utf8Validator.allocate
|
|
40
|
+
@state = :init
|
|
41
|
+
end
|
|
42
|
+
|
|
43
|
+
|
|
44
|
+
def do_keep_alive interval
|
|
45
|
+
@keep_alive_timer = ::EM::PeriodicTimer.new(interval) do
|
|
46
|
+
log_system_debug "sending keep-alive ping frame: payload_length=10" if $oversip_debug
|
|
47
|
+
@connection.send_data KEEPALIVE_PING_FRAME
|
|
48
|
+
end
|
|
49
|
+
end
|
|
50
|
+
|
|
51
|
+
|
|
52
|
+
def receive_data
|
|
53
|
+
while (case @state
|
|
54
|
+
when :init
|
|
55
|
+
return false if @buffer.size < 2
|
|
56
|
+
|
|
57
|
+
byte1 = @buffer.read(1).getbyte(0)
|
|
58
|
+
byte2 = @buffer.read(1).getbyte(0)
|
|
59
|
+
|
|
60
|
+
# FIN is the bit 0.
|
|
61
|
+
@fin = (byte1 & 0b10000000) == 0b10000000
|
|
62
|
+
|
|
63
|
+
# RSV1-3 are bits 1-3.
|
|
64
|
+
@rsv1 = (byte1 & 0b01000000) == 0b01000000
|
|
65
|
+
@rsv2 = (byte1 & 0b00100000) == 0b00100000
|
|
66
|
+
@rsv3 = (byte1 & 0b00010000) == 0b00010000
|
|
67
|
+
|
|
68
|
+
if @rsv1 or @rsv2 or @rsv3
|
|
69
|
+
log_system_notice "frame has RSV bits set, clossing the connection"
|
|
70
|
+
send_close_frame 1002, "RSV bit set not supported"
|
|
71
|
+
return false
|
|
72
|
+
end
|
|
73
|
+
|
|
74
|
+
# opcode are bits 4-7.
|
|
75
|
+
@opcode = byte1 & 0b00001111
|
|
76
|
+
unless (@sym_opcode = OPCODE[@opcode])
|
|
77
|
+
send_close_frame 1002, "unknown opcode=#{@opcode}"
|
|
78
|
+
return false
|
|
79
|
+
end
|
|
80
|
+
|
|
81
|
+
# MASK is bit 8.
|
|
82
|
+
@mask = (byte2 & 0b10000000) == 0b10000000
|
|
83
|
+
unless @mask
|
|
84
|
+
send_close_frame 1002, "MASK bit not set"
|
|
85
|
+
return false
|
|
86
|
+
end
|
|
87
|
+
|
|
88
|
+
# payload_len are bits 9-15.
|
|
89
|
+
length = byte2 & 0b01111111
|
|
90
|
+
|
|
91
|
+
case length
|
|
92
|
+
# Length defined by 8 bytes.
|
|
93
|
+
when 127
|
|
94
|
+
@state = :payload_length_8_bytes
|
|
95
|
+
# Length defined by 2 bytes.
|
|
96
|
+
when 126
|
|
97
|
+
@state = :payload_length_2_bytes
|
|
98
|
+
# Length defined by already received 7 bits.
|
|
99
|
+
else
|
|
100
|
+
@payload_length = length
|
|
101
|
+
@state = :masking_key
|
|
102
|
+
end
|
|
103
|
+
|
|
104
|
+
@payload = nil
|
|
105
|
+
true
|
|
106
|
+
|
|
107
|
+
when :payload_length_2_bytes
|
|
108
|
+
return false if @buffer.size < 2
|
|
109
|
+
|
|
110
|
+
# Get the payload length and remove first two bytes fro
|
|
111
|
+
# the buffer at the same time.
|
|
112
|
+
@payload_length = @buffer.read(2).unpack('n').first
|
|
113
|
+
|
|
114
|
+
@state = :masking_key
|
|
115
|
+
true
|
|
116
|
+
|
|
117
|
+
when :payload_length_8_bytes
|
|
118
|
+
return false if @buffer.size < 8
|
|
119
|
+
|
|
120
|
+
# Get the payload length.
|
|
121
|
+
# NOTE: Just take the last 4 bytes (4 GB frame is enough!!!),
|
|
122
|
+
# Check that first 4 bytes are 0000. If not then the frame is bigger
|
|
123
|
+
# than 4 GB and must be rejected!
|
|
124
|
+
|
|
125
|
+
if @buffer.read(4).unpack('N').first != 0
|
|
126
|
+
log_system_notice "frame size bigger than 4 GB, rejected"
|
|
127
|
+
send_close_frame 1008
|
|
128
|
+
return false
|
|
129
|
+
end
|
|
130
|
+
|
|
131
|
+
@payload_length = @buffer.read(4).unpack('N').first
|
|
132
|
+
|
|
133
|
+
@state = :masking_key
|
|
134
|
+
true
|
|
135
|
+
|
|
136
|
+
when :masking_key
|
|
137
|
+
return false if @buffer.size < 4
|
|
138
|
+
|
|
139
|
+
# Get the masking key (4 bytes) and remove first 4 bytes
|
|
140
|
+
# from the buffer.
|
|
141
|
+
@masking_key = @buffer.read(4)
|
|
142
|
+
|
|
143
|
+
@state = :check_frame
|
|
144
|
+
true
|
|
145
|
+
|
|
146
|
+
when :check_frame
|
|
147
|
+
# All control frames MUST have a payload length of 125 bytes or
|
|
148
|
+
# less and MUST NOT be fragmented.
|
|
149
|
+
if control_frame? and @payload_length > 125
|
|
150
|
+
log_system_notice "received invalid control frame (payload_length > 125), sending close frame"
|
|
151
|
+
send_close_frame 1002
|
|
152
|
+
return false
|
|
153
|
+
end
|
|
154
|
+
|
|
155
|
+
if control_frame? and not @fin
|
|
156
|
+
log_system_notice "received invalid control frame (FIN=0), sending close frame"
|
|
157
|
+
send_close_frame 1002, "forbidden FIN=0 in control frame"
|
|
158
|
+
return false
|
|
159
|
+
end
|
|
160
|
+
|
|
161
|
+
# A continuation frame can only arrive if previously a text/binary frame
|
|
162
|
+
# arrived with FIN=0.
|
|
163
|
+
if continuation_frame? and not @msg_sym_opcode
|
|
164
|
+
log_system_notice "invalid continuation frame received (no previous unfinished message), sending close frame"
|
|
165
|
+
send_close_frame 1002, "invalid continuation frame received"
|
|
166
|
+
return false
|
|
167
|
+
end
|
|
168
|
+
|
|
169
|
+
# If a previous frame had FIN=0 and opcode=text/binary, then it cannot arrive
|
|
170
|
+
# a new frame with opcode=text/binary.
|
|
171
|
+
if @msg_sym_opcode and text_or_binary_frame?
|
|
172
|
+
log_system_notice "invalid text/binary frame received (expecting a continuation frame), sending close frame"
|
|
173
|
+
send_close_frame 1002, "expected a continuation frame"
|
|
174
|
+
return false
|
|
175
|
+
end
|
|
176
|
+
|
|
177
|
+
# Check max frame size.
|
|
178
|
+
if @payload_length > @@max_frame_size
|
|
179
|
+
send_close_frame 1009, "frame too big"
|
|
180
|
+
return false
|
|
181
|
+
end
|
|
182
|
+
|
|
183
|
+
@state = :payload_data
|
|
184
|
+
true
|
|
185
|
+
|
|
186
|
+
when :payload_data
|
|
187
|
+
return false if @buffer.size < @payload_length
|
|
188
|
+
|
|
189
|
+
unless @payload_length.zero?
|
|
190
|
+
# NOTE: @payload will always be Encoding::BINARY
|
|
191
|
+
@payload = ::OverSIP::WebSocket::FramingUtils.unmask @buffer.read(@payload_length), @masking_key
|
|
192
|
+
end
|
|
193
|
+
# NOTE: @payload could be nil.
|
|
194
|
+
|
|
195
|
+
@state = :process_frame
|
|
196
|
+
true
|
|
197
|
+
|
|
198
|
+
when :process_frame
|
|
199
|
+
# Set it here as it could be changed later in this block.
|
|
200
|
+
@state = :init
|
|
201
|
+
|
|
202
|
+
case @sym_opcode
|
|
203
|
+
|
|
204
|
+
when :text
|
|
205
|
+
log_system_debug "received text frame: FIN=#{@fin}, RSV1-3=#{@rsv1}/#{@rsv2}/#{@rsv3}, payload_length=#{@payload_length}" if $oversip_debug
|
|
206
|
+
|
|
207
|
+
# Store the opcode of the first frame (if there is more frames for same message
|
|
208
|
+
# they will have opcode=continuation).
|
|
209
|
+
@msg_sym_opcode = @sym_opcode
|
|
210
|
+
|
|
211
|
+
# Reset the UTF8 validator.
|
|
212
|
+
@utf8_validator.reset
|
|
213
|
+
|
|
214
|
+
if @payload
|
|
215
|
+
if (valid_utf8 = @utf8_validator.validate(@payload)) == false
|
|
216
|
+
log_system_notice "received single text frame contains invalid UTF-8, closing the connection"
|
|
217
|
+
send_close_frame 1007, "single text frame contains invalid UTF-8"
|
|
218
|
+
return false
|
|
219
|
+
end
|
|
220
|
+
|
|
221
|
+
if @fin and not valid_utf8
|
|
222
|
+
log_system_notice "received single text frame contains incomplete UTF-8, closing the connection"
|
|
223
|
+
send_close_frame 1007, "single text frame contains incomplete UTF-8"
|
|
224
|
+
return false
|
|
225
|
+
end
|
|
226
|
+
|
|
227
|
+
return false unless @ws_app.receive_payload_data @payload
|
|
228
|
+
end
|
|
229
|
+
|
|
230
|
+
# If message is finished tell it to the WS application.
|
|
231
|
+
if @fin
|
|
232
|
+
@ws_app.message_done @msg_sym_opcode
|
|
233
|
+
@msg_sym_opcode = nil
|
|
234
|
+
end
|
|
235
|
+
|
|
236
|
+
when :binary
|
|
237
|
+
log_system_debug "received binary frame: FIN=#{@fin}, RSV1-3=#{@rsv1}/#{@rsv2}/#{@rsv3}, payload_length=#{@payload_length}" if $oversip_debug
|
|
238
|
+
|
|
239
|
+
# Store the opcode of the first frame (if there is more frames for same message
|
|
240
|
+
# they will have opcode=continuation).
|
|
241
|
+
@msg_sym_opcode = @sym_opcode
|
|
242
|
+
|
|
243
|
+
if @payload
|
|
244
|
+
return false unless @ws_app.receive_payload_data @payload
|
|
245
|
+
end
|
|
246
|
+
|
|
247
|
+
# If message is finished tell it to the WS application.
|
|
248
|
+
if @fin
|
|
249
|
+
@ws_app.message_done @msg_sym_opcode
|
|
250
|
+
@msg_sym_opcode = nil
|
|
251
|
+
end
|
|
252
|
+
|
|
253
|
+
when :continuation
|
|
254
|
+
log_system_debug "received continuation frame: FIN=#{@fin}, RSV1-3=#{@rsv1}/#{@rsv2}/#{@rsv3}, payload_length=#{@payload_length}" if $oversip_debug
|
|
255
|
+
|
|
256
|
+
if @payload
|
|
257
|
+
if @msg_sym_opcode == :text
|
|
258
|
+
if (valid_utf8 = @utf8_validator.validate(@payload)) == false
|
|
259
|
+
log_system_notice "received continuation text frame contains invalid UTF-8, closing the connection"
|
|
260
|
+
send_close_frame 1007, "continuation text frame contains invalid UTF-8"
|
|
261
|
+
return false
|
|
262
|
+
end
|
|
263
|
+
|
|
264
|
+
if @fin and not valid_utf8
|
|
265
|
+
log_system_notice "received continuation final text frame contains incomplete UTF-8, closing the connection"
|
|
266
|
+
send_close_frame 1007, "continuation final text frame contains incomplete UTF-8"
|
|
267
|
+
return false
|
|
268
|
+
end
|
|
269
|
+
end
|
|
270
|
+
|
|
271
|
+
return false unless @ws_app.receive_payload_data @payload
|
|
272
|
+
end
|
|
273
|
+
|
|
274
|
+
# If message is finished tell it to the WS application.
|
|
275
|
+
if @fin
|
|
276
|
+
@ws_app.message_done @msg_sym_opcode
|
|
277
|
+
@msg_sym_opcode = nil
|
|
278
|
+
end
|
|
279
|
+
|
|
280
|
+
when :close
|
|
281
|
+
if @payload_length >= 2
|
|
282
|
+
status = ""
|
|
283
|
+
status << @payload.getbyte(0) << @payload.getbyte(1)
|
|
284
|
+
status = status.unpack('n').first
|
|
285
|
+
if (reason = @payload[2..-1])
|
|
286
|
+
# Reset the UTF8 validator.
|
|
287
|
+
@utf8_validator.reset
|
|
288
|
+
|
|
289
|
+
# The UTF-8 validator returns:
|
|
290
|
+
# - true: Valid UTF-8 string.
|
|
291
|
+
# - nil: Valid but not terminated UTF-8 string.
|
|
292
|
+
# - false: Invalid UTF-8 string.
|
|
293
|
+
# So it must be true for the close frame reason.
|
|
294
|
+
unless @utf8_validator.validate(reason)
|
|
295
|
+
log_system_notice "received close frame with invalid UTF-8 data in the reason: status=#{status.inspect}"
|
|
296
|
+
send_close_frame 1007, "close frame reason contains incomplete UTF-8"
|
|
297
|
+
return false
|
|
298
|
+
end
|
|
299
|
+
end
|
|
300
|
+
else
|
|
301
|
+
status = nil
|
|
302
|
+
end
|
|
303
|
+
|
|
304
|
+
case status
|
|
305
|
+
when 1002
|
|
306
|
+
log_system_notice "received close frame due to WS protocol error: status=1002, reason=#{reason.inspect}"
|
|
307
|
+
when 1003
|
|
308
|
+
log_system_notice "received close frame due to sent data type: status=1003, reason=#{reason.inspect}"
|
|
309
|
+
when 1007
|
|
310
|
+
log_system_notice "received close frame due to non valid UTF-8 data sent: status=1007, reason=#{reason.inspect}"
|
|
311
|
+
when 1009
|
|
312
|
+
log_system_notice "received close frame due to too big message sent: status=1009, reason=#{reason.inspect}"
|
|
313
|
+
when 1010
|
|
314
|
+
log_system_notice "received close frame due to extensions negotiation failure: status=1010, reason=#{reason.inspect}"
|
|
315
|
+
else
|
|
316
|
+
log_system_debug "received close frame: status=#{status.inspect}, reason=#{reason.inspect}" if $oversip_debug
|
|
317
|
+
end
|
|
318
|
+
|
|
319
|
+
send_close_frame nil, nil, true
|
|
320
|
+
return false
|
|
321
|
+
|
|
322
|
+
when :ping
|
|
323
|
+
log_system_debug "received ping frame: payload_length=#{@payload_length}" if $oversip_debug
|
|
324
|
+
send_pong_frame @payload
|
|
325
|
+
|
|
326
|
+
when :pong
|
|
327
|
+
log_system_debug "received pong frame: payload_length=#{@payload_length}" if $oversip_debug
|
|
328
|
+
|
|
329
|
+
end
|
|
330
|
+
|
|
331
|
+
true
|
|
332
|
+
|
|
333
|
+
when :ws_closed
|
|
334
|
+
false
|
|
335
|
+
|
|
336
|
+
when :tcp_closed
|
|
337
|
+
false
|
|
338
|
+
|
|
339
|
+
end)
|
|
340
|
+
end # while
|
|
341
|
+
|
|
342
|
+
end # receive_data
|
|
343
|
+
|
|
344
|
+
|
|
345
|
+
def control_frame?
|
|
346
|
+
@opcode > 2
|
|
347
|
+
end
|
|
348
|
+
|
|
349
|
+
|
|
350
|
+
def text_or_binary_frame?
|
|
351
|
+
@opcode == 1 or @opcode == 2
|
|
352
|
+
end
|
|
353
|
+
|
|
354
|
+
|
|
355
|
+
def continuation_frame?
|
|
356
|
+
@opcode == 0
|
|
357
|
+
end
|
|
358
|
+
|
|
359
|
+
|
|
360
|
+
# NOTE: A WS message is always set in a single WS frame.
|
|
361
|
+
def send_text_frame message
|
|
362
|
+
case @state
|
|
363
|
+
when :ws_closed
|
|
364
|
+
log_system_debug "cannot send text frame, WebSocket session is closed" if $oversip_debug
|
|
365
|
+
return false
|
|
366
|
+
when :tcp_closed
|
|
367
|
+
log_system_debug "cannot send text frame, TCP session is closed" if $oversip_debug
|
|
368
|
+
return false
|
|
369
|
+
end
|
|
370
|
+
log_system_debug "sending text frame: payload_length=#{message.bytesize}" if $oversip_debug
|
|
371
|
+
|
|
372
|
+
frame = "".encode ::Encoding::BINARY
|
|
373
|
+
|
|
374
|
+
# byte1 = OPCODE_TO_INT[:text] | 0b10000000 => 129
|
|
375
|
+
#
|
|
376
|
+
# - FIN bit set.
|
|
377
|
+
# - RSV1-3 bits not set.
|
|
378
|
+
# - opcode = 1
|
|
379
|
+
frame << 129
|
|
380
|
+
|
|
381
|
+
length = message.bytesize
|
|
382
|
+
if length <= 125
|
|
383
|
+
frame << length # since rsv4 is 0
|
|
384
|
+
elsif length < 65536 # write 2 byte length
|
|
385
|
+
frame << 126
|
|
386
|
+
frame << [length].pack('n')
|
|
387
|
+
else # write 8 byte length
|
|
388
|
+
frame << 127
|
|
389
|
+
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
|
390
|
+
end
|
|
391
|
+
|
|
392
|
+
if message.encoding == ::Encoding::BINARY
|
|
393
|
+
frame << message
|
|
394
|
+
else
|
|
395
|
+
frame << message.force_encoding(::Encoding::BINARY)
|
|
396
|
+
end
|
|
397
|
+
|
|
398
|
+
@connection.send_data frame
|
|
399
|
+
true
|
|
400
|
+
end
|
|
401
|
+
|
|
402
|
+
|
|
403
|
+
def send_binary_frame message
|
|
404
|
+
case @state
|
|
405
|
+
when :ws_closed
|
|
406
|
+
log_system_debug "cannot send binary frame, WebSocket session is closed" if $oversip_debug
|
|
407
|
+
return false
|
|
408
|
+
when :tcp_closed
|
|
409
|
+
log_system_debug "cannot send binary frame, TCP session is closed" if $oversip_debug
|
|
410
|
+
return false
|
|
411
|
+
end
|
|
412
|
+
log_system_debug "sending binary frame: payload_length=#{message.bytesize}" if $oversip_debug
|
|
413
|
+
|
|
414
|
+
frame = "".encode ::Encoding::BINARY
|
|
415
|
+
|
|
416
|
+
# byte1 = OPCODE_TO_INT[:binary] | 0b10000000 => 130
|
|
417
|
+
#
|
|
418
|
+
# - FIN bit set.
|
|
419
|
+
# - RSV1-3 bits not set.
|
|
420
|
+
# - opcode = 2
|
|
421
|
+
frame << 130
|
|
422
|
+
|
|
423
|
+
length = message.bytesize
|
|
424
|
+
if length <= 125
|
|
425
|
+
frame << length # since rsv4 is 0
|
|
426
|
+
elsif length < 65536 # write 2 byte length
|
|
427
|
+
frame << 126
|
|
428
|
+
frame << [length].pack('n')
|
|
429
|
+
else # write 8 byte length
|
|
430
|
+
frame << 127
|
|
431
|
+
frame << [length >> 32, length & 0xFFFFFFFF].pack("NN")
|
|
432
|
+
end
|
|
433
|
+
|
|
434
|
+
if message.encoding == ::Encoding::BINARY
|
|
435
|
+
frame << message
|
|
436
|
+
else
|
|
437
|
+
frame << message.force_encoding(::Encoding::BINARY)
|
|
438
|
+
end
|
|
439
|
+
|
|
440
|
+
@connection.send_data frame
|
|
441
|
+
true
|
|
442
|
+
end
|
|
443
|
+
|
|
444
|
+
|
|
445
|
+
def send_ping_frame data=nil
|
|
446
|
+
case @state
|
|
447
|
+
when :ws_closed
|
|
448
|
+
log_system_debug "cannot send ping frame, WebSocket session is closed" if $oversip_debug
|
|
449
|
+
return false
|
|
450
|
+
when :tcp_closed
|
|
451
|
+
log_system_debug "cannot send ping frame, TCP session is closed" if $oversip_debug
|
|
452
|
+
return false
|
|
453
|
+
end
|
|
454
|
+
if data
|
|
455
|
+
log_system_debug "sending ping frame: payload_length=#{data.bytesize}" if $oversip_debug
|
|
456
|
+
else
|
|
457
|
+
log_system_debug "sending ping frame: payload_length=0" if $oversip_debug
|
|
458
|
+
end
|
|
459
|
+
|
|
460
|
+
frame = "".encode ::Encoding::BINARY
|
|
461
|
+
|
|
462
|
+
# byte1 = OPCODE_TO_INT[:ping] | 0b10000000 => 137
|
|
463
|
+
#
|
|
464
|
+
# - FIN bit set.
|
|
465
|
+
# - RSV1-3 bits not set.
|
|
466
|
+
# - opcode = 9
|
|
467
|
+
frame << 137
|
|
468
|
+
|
|
469
|
+
length = ( data ? data.bytesize : 0 )
|
|
470
|
+
frame << length
|
|
471
|
+
|
|
472
|
+
if data
|
|
473
|
+
if data.encoding == ::Encoding::BINARY
|
|
474
|
+
frame << data
|
|
475
|
+
else
|
|
476
|
+
frame << data.force_encoding(::Encoding::BINARY)
|
|
477
|
+
end
|
|
478
|
+
end
|
|
479
|
+
|
|
480
|
+
@connection.send_data frame
|
|
481
|
+
true
|
|
482
|
+
end
|
|
483
|
+
|
|
484
|
+
|
|
485
|
+
def send_pong_frame data=nil
|
|
486
|
+
case @state
|
|
487
|
+
when :ws_closed
|
|
488
|
+
log_system_debug "cannot send pong frame, WebSocket session is closed" if $oversip_debug
|
|
489
|
+
return false
|
|
490
|
+
when :tcp_closed
|
|
491
|
+
log_system_debug "cannot send pong frame, TCP session is closed" if $oversip_debug
|
|
492
|
+
return false
|
|
493
|
+
end
|
|
494
|
+
if data
|
|
495
|
+
log_system_debug "sending pong frame: payload_length=#{data.bytesize}" if $oversip_debug
|
|
496
|
+
else
|
|
497
|
+
log_system_debug "sending pong frame: payload_length=0" if $oversip_debug
|
|
498
|
+
end
|
|
499
|
+
|
|
500
|
+
frame = "".encode ::Encoding::BINARY
|
|
501
|
+
|
|
502
|
+
# byte1 = OPCODE_TO_INT[:pong] | 0b10000000 => 138
|
|
503
|
+
#
|
|
504
|
+
# - FIN bit set.
|
|
505
|
+
# - RSV1-3 bits not set.
|
|
506
|
+
# - opcode = 10
|
|
507
|
+
frame << 138
|
|
508
|
+
|
|
509
|
+
length = ( data ? data.bytesize : 0 )
|
|
510
|
+
frame << length
|
|
511
|
+
|
|
512
|
+
if data
|
|
513
|
+
if data.encoding == ::Encoding::BINARY
|
|
514
|
+
frame << data
|
|
515
|
+
else
|
|
516
|
+
frame << data.force_encoding(::Encoding::BINARY)
|
|
517
|
+
end
|
|
518
|
+
end
|
|
519
|
+
|
|
520
|
+
@connection.send_data frame
|
|
521
|
+
true
|
|
522
|
+
end
|
|
523
|
+
|
|
524
|
+
|
|
525
|
+
def send_close_frame status=nil, reason=nil, in_reply_to_close=nil
|
|
526
|
+
@keep_alive_timer.cancel if @keep_alive_timer
|
|
527
|
+
|
|
528
|
+
case @state
|
|
529
|
+
when :ws_closed
|
|
530
|
+
log_system_debug "cannot send close frame, WebSocket session is closed" if $oversip_debug
|
|
531
|
+
return false
|
|
532
|
+
when :tcp_closed
|
|
533
|
+
log_system_debug "cannot send close frame, TCP session is closed" if $oversip_debug
|
|
534
|
+
return false
|
|
535
|
+
end
|
|
536
|
+
|
|
537
|
+
unless in_reply_to_close
|
|
538
|
+
log_system_notice "sending close frame: status=#{status.inspect}, reason=#{reason.inspect}"
|
|
539
|
+
else
|
|
540
|
+
log_system_debug "sending reply close frame: status=#{status.inspect}, reason=#{reason.inspect}" if $oversip_debug
|
|
541
|
+
end
|
|
542
|
+
|
|
543
|
+
@state = :ws_closed
|
|
544
|
+
@buffer.clear
|
|
545
|
+
|
|
546
|
+
frame = "".encode ::Encoding::BINARY
|
|
547
|
+
|
|
548
|
+
# byte1 = OPCODE_TO_INT[:close] | 0b10000000 => 136
|
|
549
|
+
#
|
|
550
|
+
# - FIN bit set.
|
|
551
|
+
# - RSV1-3 bits not set.
|
|
552
|
+
# - opcode = 8
|
|
553
|
+
frame << 136
|
|
554
|
+
if status
|
|
555
|
+
length = ( reason ? 2 + reason.bytesize : 2 )
|
|
556
|
+
else
|
|
557
|
+
length = 0
|
|
558
|
+
end
|
|
559
|
+
|
|
560
|
+
frame << length # since rsv4 is 0
|
|
561
|
+
if status
|
|
562
|
+
frame << [status].pack('n')
|
|
563
|
+
if reason
|
|
564
|
+
if reason.encoding == ::Encoding::BINARY
|
|
565
|
+
frame << reason
|
|
566
|
+
else
|
|
567
|
+
frame << reason.force_encoding(::Encoding::BINARY)
|
|
568
|
+
end
|
|
569
|
+
end
|
|
570
|
+
end
|
|
571
|
+
|
|
572
|
+
@connection.ignore_incoming_data
|
|
573
|
+
@connection.send_data frame
|
|
574
|
+
|
|
575
|
+
unless in_reply_to_close
|
|
576
|
+
# Let's some time for the client to send us a close frame (it will
|
|
577
|
+
# be ignored anyway) before closing the TCP connection.
|
|
578
|
+
EM.add_timer(0.2) do
|
|
579
|
+
@connection.close_connection_after_writing
|
|
580
|
+
end
|
|
581
|
+
else
|
|
582
|
+
@connection.close_connection_after_writing
|
|
583
|
+
end
|
|
584
|
+
true
|
|
585
|
+
end
|
|
586
|
+
|
|
587
|
+
|
|
588
|
+
def tcp_closed
|
|
589
|
+
@keep_alive_timer.cancel if @keep_alive_timer
|
|
590
|
+
@state = :tcp_closed
|
|
591
|
+
# Tell it to the WS application.
|
|
592
|
+
@ws_app.tcp_closed rescue nil
|
|
593
|
+
end
|
|
594
|
+
|
|
595
|
+
end # class WsFraming
|
|
596
|
+
|
|
597
|
+
end
|
data/lib/oversip.rb
ADDED
|
@@ -0,0 +1,59 @@
|
|
|
1
|
+
# Ruby built-in libraries.
|
|
2
|
+
|
|
3
|
+
require "etc"
|
|
4
|
+
require "fileutils"
|
|
5
|
+
require "socket"
|
|
6
|
+
require "timeout"
|
|
7
|
+
require "yaml"
|
|
8
|
+
require "tempfile"
|
|
9
|
+
|
|
10
|
+
|
|
11
|
+
# Ruby external gems.
|
|
12
|
+
|
|
13
|
+
require "term/ansicolor"
|
|
14
|
+
require "posix_mq"
|
|
15
|
+
|
|
16
|
+
|
|
17
|
+
# OverSIP files.
|
|
18
|
+
|
|
19
|
+
require "oversip/version.rb"
|
|
20
|
+
require "oversip/logger.rb"
|
|
21
|
+
require "oversip/config.rb"
|
|
22
|
+
require "oversip/config_validators.rb"
|
|
23
|
+
require "oversip/proxies_config.rb"
|
|
24
|
+
require "oversip/errors.rb"
|
|
25
|
+
require "oversip/launcher.rb"
|
|
26
|
+
require "oversip/utils.so"
|
|
27
|
+
require "oversip/utils.rb"
|
|
28
|
+
require "oversip/posix_mq.rb"
|
|
29
|
+
|
|
30
|
+
|
|
31
|
+
|
|
32
|
+
|
|
33
|
+
module OverSIP
|
|
34
|
+
|
|
35
|
+
class << self
|
|
36
|
+
attr_accessor :pid_file, :master_name, :master_pid, :daemonized,
|
|
37
|
+
:syslogger_pid, :syslogger_mq_name,
|
|
38
|
+
:configuration,
|
|
39
|
+
:proxies,
|
|
40
|
+
:tls, :tls_public_cert, :tls_private_cert, :tls_proxy_ipv4, :tls_proxy_ipv6
|
|
41
|
+
|
|
42
|
+
def master?
|
|
43
|
+
@master_pid == $$
|
|
44
|
+
end
|
|
45
|
+
|
|
46
|
+
def daemonized?
|
|
47
|
+
@daemonized
|
|
48
|
+
end
|
|
49
|
+
|
|
50
|
+
def syslogger_ready?
|
|
51
|
+
@syslogger_pid and true
|
|
52
|
+
end
|
|
53
|
+
end
|
|
54
|
+
|
|
55
|
+
# Pre-declare internal modules.
|
|
56
|
+
module SIP ; end
|
|
57
|
+
module WebSocket ; end
|
|
58
|
+
|
|
59
|
+
end
|
|
@@ -0,0 +1,20 @@
|
|
|
1
|
+
require "test/unit"
|
|
2
|
+
require "oversip"
|
|
3
|
+
require "oversip/master_process"
|
|
4
|
+
|
|
5
|
+
|
|
6
|
+
class OverSIPTest < Test::Unit::TestCase
|
|
7
|
+
|
|
8
|
+
def assert_true(object, message="")
|
|
9
|
+
assert_equal(object, true, message)
|
|
10
|
+
end
|
|
11
|
+
|
|
12
|
+
def assert_false(object, message="")
|
|
13
|
+
assert_equal(object, false, message)
|
|
14
|
+
end
|
|
15
|
+
|
|
16
|
+
def assert_equal_options(options, element)
|
|
17
|
+
assert options.include?(element)
|
|
18
|
+
end
|
|
19
|
+
|
|
20
|
+
end
|