Class: OverSIP::WebSocket::WsServer
- Inherits:
-
Connection
- Object
- EM::Connection
- Connection
- OverSIP::WebSocket::WsServer
show all
- Defined in:
- lib/oversip/websocket/listeners/ws_server.rb
Constant Summary
collapse
2048
- WS_MAGIC_GUID_04 =
"258EAFA5-E914-47DA-95CA-C5AB0DC85B11".freeze
- WS_VERSIONS =
{ 7=>true, 8=>true, 13=>true }
- HDR_SUPPORTED_WEBSOCKET_VERSIONS =
[ "X-Supported-WebSocket-Versions: #{WS_VERSIONS.keys.join(", ")}" ]
SIP::MessageProcessor::MSG_TYPE
Instance Attribute Summary collapse
Attributes inherited from Connection
#cvars
Instance Method Summary
collapse
Methods inherited from Connection
#close, #initialize, #open?, outbound_listener?, reliable_transport_listener?
Methods included from Logger
close, fg_system_msg2str, init_logger_mq, load_methods, #log_id, syslog_system_msg2str, syslog_user_msg2str
Instance Attribute Details
#client_closed=(value) ⇒ Object
Sets the attribute client_closed
15
16
17
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 15
def client_closed=(value)
@client_closed = value
end
|
#outbound_flow_token ⇒ Object
Returns the value of attribute outbound_flow_token.
14
15
16
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 14
def outbound_flow_token
@outbound_flow_token
end
|
#ws_established=(value) ⇒ Object
Sets the attribute ws_established
15
16
17
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 15
def ws_established=(value)
@ws_established = value
end
|
Instance Method Details
#accept_ws_handshake ⇒ Object
273
274
275
276
277
278
279
280
281
282
283
284
285
286
287
288
289
290
291
292
293
294
295
296
297
298
299
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 273
def accept_ws_handshake
sec_websocket_accept = Digest::SHA1::base64digest @http_request.hdr_sec_websocket_key + WS_MAGIC_GUID_04
= [
"Upgrade: websocket",
"Connection: Upgrade",
"Sec-WebSocket-Accept: #{sec_websocket_accept}"
]
if @websocket_protocol_negotiated
<< "Sec-WebSocket-Protocol: #{WS_SIP_PROTOCOL}"
end
if @websocket_extensions
<< "Sec-WebSocket-Extensions: #{@websocket_extensions.to_s}"
end
@http_request.reply 101, nil,
@ws_framing = ::OverSIP::WebSocket::WsFraming.new self, @buffer
ws_sip_app = ::OverSIP::WebSocket::WsSipApp.new self, @ws_framing
@ws_framing.ws_app = ws_sip_app
@state = :websocket
true
end
|
#check_http_request ⇒ Object
178
179
180
181
182
183
184
185
186
187
188
189
190
191
192
193
194
195
196
197
198
199
200
201
202
203
204
205
206
207
208
209
210
211
212
213
214
215
216
217
218
219
220
221
222
223
224
225
226
227
228
229
230
231
232
233
234
235
236
237
238
239
240
241
242
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 178
def check_http_request
unless ::OverSIP.status == :running
case ::OverSIP.status
when :loading
http_reject 500, "Server Still Loading", [ "Retry-After: 5" ]
when :terminating
http_reject 500, "Server is Being Stopped"
end
return false
end
if @http_request.http_method != :GET
log_system_notice "rejecting HTTP #{@http_request.http_method} request => 405"
http_reject 405
return false
end
unless WS_VERSIONS[@http_request.hdr_sec_websocket_version]
if @http_request.hdr_sec_websocket_version
log_system_notice "WebSocket version #{@http_request.hdr_sec_websocket_version} not implemented => 426"
else
log_system_notice "WebSocket version header not present => 426"
end
http_reject 426, nil, HDR_SUPPORTED_WEBSOCKET_VERSIONS
return false
end
unless @http_request.hdr_connection and @http_request.hdr_connection.include? "upgrade"
log_system_notice "Connection header must include \"upgrade\" => 400"
http_reject 400, "Connection header must include \"upgrade\""
return false
end
unless @http_request.hdr_upgrade == "websocket"
log_system_notice "Upgrade header must be \"websocket\" => 400"
http_reject 400, "Upgrade header must be \"websocket\""
return false
end
unless @http_request.hdr_sec_websocket_key
log_system_notice "Sec-WebSocket-Key header not present => 400"
http_reject 400, "Sec-WebSocket-Key header not present"
return false
end
if @http_request.hdr_sec_websocket_protocol
if @http_request.hdr_sec_websocket_protocol.include? WS_SIP_PROTOCOL
@websocket_protocol_negotiated = true
else
log_system_notice "Sec-WebSocket-Protocol does not contain a supported protocol but #{@http_request.hdr_sec_websocket_protocol} => 501"
http_reject 501, "No Suitable WebSocket Protocol"
return false
end
end
@state = :on_connection_callback
true
end
|
#do_on_connection_callback ⇒ Object
245
246
247
248
249
250
251
252
253
254
255
256
257
258
259
260
261
262
263
264
265
266
267
268
269
270
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 245
def do_on_connection_callback
@state = :waiting_for_on_connection
::Fiber.new do
begin
log_system_debug "running OverSIP::WebSocketEvents.on_connection()..." if $oversip_debug
::OverSIP::WebSocketEvents.on_connection self, @http_request
unless @local_closed or error?
@state = :accept_ws_handshake
process_received_data
else
log_system_debug "connection closed during OverSIP::WebSocketEvents.on_connection(), aborting" if $oversip_debug
end
rescue ::Exception => e
log_system_error "error calling OverSIP::WebSocketEvents.on_connection() => 500:"
log_system_error e
http_reject 500
end
end.resume
end
|
#http_reject(status_code = 403, reason_phrase = nil, extra_headers = nil) ⇒ Object
302
303
304
305
306
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 302
def http_reject status_code=403, reason_phrase=nil, =nil
@http_request.reply(status_code, reason_phrase, )
close_connection_after_writing
@state = :ignore
end
|
147
148
149
150
151
152
153
154
155
156
157
158
159
160
161
162
163
164
165
166
167
168
169
170
171
172
173
174
175
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 147
def
return false if @buffer.empty?
unless @http_parser_nbytes = @http_parser.execute(@http_request, @buffer.to_str, @http_parser_nbytes)
log_system_warn "parsing error: \"#{@http_parser.error}\""
close_connection_after_writing
@state = :ignore
return false
end
if @http_parser_nbytes > HEADERS_MAX_SIZE
log_system_warn "DoS attack detected: headers size exceedes #{HEADERS_MAX_SIZE} bytes, closing connection with #{remote_desc}"
close_connection
@state = :ignore
return false
end
return false unless @http_parser.finished?
@buffer.read(@http_parser_nbytes)
@http_request.connection = self
@state = :check_http_request
true
end
|
#post_connection ⇒ Object
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 34
def post_connection
begin
@remote_port, @remote_ip = ::Socket.unpack_sockaddr_in(get_peername)
rescue => e
log_system_error "error obtaining remote IP/port (#{e.class}: #{e.message}), closing connection"
close_connection
@state = :ignore
return
end
@connection_id = ::OverSIP::SIP::TransportManager.add_connection self, self.class, self.class.ip_type, @remote_ip, @remote_port
@outbound_flow_token = ::OverSIP::SIP::TransportManager.add_outbound_connection self
log_system_debug("connection opened from " << remote_desc) if $oversip_debug
end
|
#process_received_data ⇒ Object
110
111
112
113
114
115
116
117
118
119
120
121
122
123
124
125
126
127
128
129
130
131
132
133
134
135
136
137
138
139
140
141
142
143
144
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 110
def process_received_data
@state == :ignore and return
while (case @state
when :init
@http_parser = ::OverSIP::WebSocket::HttpRequestParser.new
@http_request = ::OverSIP::WebSocket::HttpRequest.new
@http_parser_nbytes = 0
@bytes_remaining = 0
@state = :http_headers
when :http_headers
when :check_http_request
check_http_request
when :on_connection_callback
do_on_connection_callback
false
when :accept_ws_handshake
accept_ws_handshake
when :websocket
@ws_established = true
@ws_framing.receive_data
false
when :ignore
false
end)
end
end
|
#receive_data(data) ⇒ Object
101
102
103
104
105
106
107
108
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 101
def receive_data data
@state == :ignore and return
@buffer << data
@state == :waiting_for_on_client_tls_handshake and return
@state == :waiting_for_on_connection and return
process_received_data
end
|
#remote_desc(force = nil) ⇒ Object
53
54
55
56
57
58
59
60
61
62
63
64
65
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 53
def remote_desc force=nil
if force
@remote_desc = case @remote_ip_type
when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
end
else
@remote_desc ||= case self.class.ip_type
when :ipv4 ; "#{@remote_ip}:#{@remote_port.to_s}"
when :ipv6 ; "[#{@remote_ip}]:#{@remote_port.to_s}"
end
end
end
|
#remote_ip ⇒ Object
22
23
24
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 22
def remote_ip
@remote_ip
end
|
#remote_ip_type ⇒ Object
18
19
20
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 18
def remote_ip_type
@remote_ip_type || self.class.ip_type
end
|
#remote_port ⇒ Object
26
27
28
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 26
def remote_port
@remote_port
end
|
#send_sip_msg(msg, ip = nil, port = nil) ⇒ Object
Parameters ip and port are just included because they are needed in UDP, so the API remains equal.
310
311
312
313
314
315
316
317
318
319
320
321
322
323
324
325
326
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 310
def send_sip_msg msg, ip=nil, port=nil
if self.error?
log_system_notice "SIP message could not be sent, connection is closed"
return false
end
if msg.force_encoding(::Encoding::UTF_8).valid_encoding?
@ws_framing.send_text_frame msg
else
@ws_framing.send_binary_frame msg
end
true
end
|
#transport ⇒ Object
30
31
32
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 30
def transport
self.class.transport
end
|
#unbind(cause = nil) ⇒ Object
68
69
70
71
72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
95
96
97
98
|
# File 'lib/oversip/websocket/listeners/ws_server.rb', line 68
def unbind cause=nil
@state = :ignore
self.class.connections.delete @connection_id
::OverSIP::SIP::TransportManager.delete_outbound_connection @outbound_flow_token
@local_closed = true if cause == ::Errno::ETIMEDOUT
@local_closed = false if @client_closed
if $oversip_debug
log_msg = "connection from #{remote_desc} "
log_msg << ( @local_closed ? "locally closed" : "remotely closed" )
log_msg << " (cause: #{cause.inspect})" if cause
log_system_debug log_msg
end unless $!
if @ws_established
::Fiber.new do
begin
::OverSIP::WebSocketEvents.on_disconnection self, !@local_closed
rescue ::Exception => e
log_system_error "error calling OverSIP::WebSocketEvents.on_disconnection():"
log_system_error e
end
end.resume
end unless $!
end
|