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,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