oversip_p 1.0.0

Sign up to get free protection for your applications and to get access to all the features.
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,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