iodine 0.1.21 → 0.2.0

Sign up to get free protection for your applications and to get access to all the features.

Potentially problematic release.


This version of iodine might be problematic. Click here for more details.

Files changed (105) hide show
  1. checksums.yaml +4 -4
  2. data/.gitignore +3 -2
  3. data/.travis.yml +23 -2
  4. data/CHANGELOG.md +9 -2
  5. data/README.md +232 -179
  6. data/Rakefile +13 -1
  7. data/bin/config.ru +63 -0
  8. data/bin/console +6 -0
  9. data/bin/echo +42 -32
  10. data/bin/http-hello +62 -0
  11. data/bin/http-playground +124 -0
  12. data/bin/playground +62 -0
  13. data/bin/poc/Gemfile.lock +23 -0
  14. data/bin/poc/README.md +37 -0
  15. data/bin/poc/config.ru +66 -0
  16. data/bin/poc/gemfile +1 -0
  17. data/bin/poc/www/index.html +57 -0
  18. data/bin/raw-rbhttp +35 -0
  19. data/bin/raw_broadcast +66 -0
  20. data/bin/test_with_faye +40 -0
  21. data/bin/ws-broadcast +108 -0
  22. data/bin/ws-echo +108 -0
  23. data/exe/iodine +59 -0
  24. data/ext/iodine/base64.c +264 -0
  25. data/ext/iodine/base64.h +72 -0
  26. data/ext/iodine/bscrypt-common.h +109 -0
  27. data/ext/iodine/bscrypt.h +49 -0
  28. data/ext/iodine/extconf.rb +41 -0
  29. data/ext/iodine/hex.c +123 -0
  30. data/ext/iodine/hex.h +70 -0
  31. data/ext/iodine/http.c +200 -0
  32. data/ext/iodine/http.h +128 -0
  33. data/ext/iodine/http1.c +402 -0
  34. data/ext/iodine/http1.h +56 -0
  35. data/ext/iodine/http1_simple_parser.c +473 -0
  36. data/ext/iodine/http1_simple_parser.h +59 -0
  37. data/ext/iodine/http_request.h +128 -0
  38. data/ext/iodine/http_response.c +1606 -0
  39. data/ext/iodine/http_response.h +393 -0
  40. data/ext/iodine/http_response_http1.h +374 -0
  41. data/ext/iodine/iodine_core.c +641 -0
  42. data/ext/iodine/iodine_core.h +70 -0
  43. data/ext/iodine/iodine_http.c +615 -0
  44. data/ext/iodine/iodine_http.h +19 -0
  45. data/ext/iodine/iodine_websocket.c +430 -0
  46. data/ext/iodine/iodine_websocket.h +21 -0
  47. data/ext/iodine/libasync.c +552 -0
  48. data/ext/iodine/libasync.h +117 -0
  49. data/ext/iodine/libreact.c +347 -0
  50. data/ext/iodine/libreact.h +244 -0
  51. data/ext/iodine/libserver.c +912 -0
  52. data/ext/iodine/libserver.h +435 -0
  53. data/ext/iodine/libsock.c +950 -0
  54. data/ext/iodine/libsock.h +478 -0
  55. data/ext/iodine/misc.c +181 -0
  56. data/ext/iodine/misc.h +76 -0
  57. data/ext/iodine/random.c +193 -0
  58. data/ext/iodine/random.h +48 -0
  59. data/ext/iodine/rb-call.c +127 -0
  60. data/ext/iodine/rb-call.h +60 -0
  61. data/ext/iodine/rb-libasync.h +79 -0
  62. data/ext/iodine/rb-rack-io.c +389 -0
  63. data/ext/iodine/rb-rack-io.h +17 -0
  64. data/ext/iodine/rb-registry.c +213 -0
  65. data/ext/iodine/rb-registry.h +33 -0
  66. data/ext/iodine/sha1.c +359 -0
  67. data/ext/iodine/sha1.h +85 -0
  68. data/ext/iodine/sha2.c +825 -0
  69. data/ext/iodine/sha2.h +138 -0
  70. data/ext/iodine/siphash.c +136 -0
  71. data/ext/iodine/siphash.h +15 -0
  72. data/ext/iodine/spnlock.h +235 -0
  73. data/ext/iodine/websockets.c +696 -0
  74. data/ext/iodine/websockets.h +120 -0
  75. data/ext/iodine/xor-crypt.c +189 -0
  76. data/ext/iodine/xor-crypt.h +107 -0
  77. data/iodine.gemspec +25 -18
  78. data/lib/iodine.rb +57 -58
  79. data/lib/iodine/http.rb +0 -189
  80. data/lib/iodine/protocol.rb +36 -245
  81. data/lib/iodine/version.rb +1 -1
  82. data/lib/rack/handler/iodine.rb +145 -2
  83. metadata +115 -37
  84. data/bin/core_http_test +0 -51
  85. data/bin/em playground +0 -56
  86. data/bin/hello_world +0 -75
  87. data/bin/setup +0 -7
  88. data/lib/iodine/client.rb +0 -5
  89. data/lib/iodine/core.rb +0 -102
  90. data/lib/iodine/core_init.rb +0 -143
  91. data/lib/iodine/http/hpack.rb +0 -553
  92. data/lib/iodine/http/http1.rb +0 -251
  93. data/lib/iodine/http/http2.rb +0 -507
  94. data/lib/iodine/http/rack_support.rb +0 -108
  95. data/lib/iodine/http/request.rb +0 -462
  96. data/lib/iodine/http/response.rb +0 -474
  97. data/lib/iodine/http/session.rb +0 -143
  98. data/lib/iodine/http/websocket_client.rb +0 -335
  99. data/lib/iodine/http/websocket_handler.rb +0 -101
  100. data/lib/iodine/http/websockets.rb +0 -336
  101. data/lib/iodine/io.rb +0 -56
  102. data/lib/iodine/logging.rb +0 -46
  103. data/lib/iodine/settings.rb +0 -158
  104. data/lib/iodine/ssl_connector.rb +0 -48
  105. data/lib/iodine/timers.rb +0 -95
@@ -1,101 +0,0 @@
1
-
2
- module Iodine
3
- module Http
4
-
5
- # This class is a good demonstration for creating a Websocket handler with the Iodine API.
6
- #
7
- # Iodine is Object Oriented and for this reason the Websocket handler is expected to
8
- # retain the information it needs - either through initialization, or through the `on_open(protocol)` callback.
9
- class WebsocketHandler
10
- # The original Http request
11
- attr_reader :request
12
- # The Http response, also allowing for websocket data
13
- attr_reader :response
14
- # this shoulw be called while still communicating over Http,
15
- # as part of the "upgrade" process. The new object should be returned by the {Iodine::Http#on_websocket} handler.
16
- #
17
- # i.e.:
18
- #
19
- # Iodine::Http.on_websocket do |request, response|
20
- # next if request.path =~ /refuse/
21
- # Iodine::Http::WebsocketHandler.new request, response
22
- # end
23
- #
24
- #
25
- # see also the {WebsocketHandler.call} method for an example.
26
- def initialize request, response
27
- @request = request
28
- @response = response
29
- end
30
- # initialize the protocol data once the connection had opened.
31
- def on_open
32
- end
33
- # Accept data using this callback - this is a required callback.
34
- def on_message data
35
- end
36
- # Accept unicasts or broadcasts using this callback.
37
- def on_broadcast data
38
- end
39
- # cleanup, if needed, using this callback.
40
- def on_close
41
- end
42
- # called whenever a ping is sent (no data transfer caused timeout).
43
- def on_ping
44
- end
45
- # extra cleanup, if needed, when server is shutting down while the websocket is connected.
46
- #
47
- # You can use on_close unless some "going away" cleanup is required.
48
- def on_shutdown
49
- end
50
-
51
- # This method allows the class itself to act as the global Websocket handler, accepting websocket connections. Example use:
52
- #
53
- # # Iodine::Http::WebsocketHandler's default implementation does nothing.
54
- # Iodine::Http.on_websocket Iodine::Http::WebsocketHandler
55
- def self.call request, response
56
- self.new request, response
57
- end
58
-
59
- protected
60
-
61
- ### some helper methods
62
-
63
- # Write data to the client, using Websockets encoded frames.
64
- def write data
65
- # We can use Websocket#send_data or it's alias Websocket#<< for example:
66
- #
67
- # # @request[:io] contains the Websockets Protocol instance
68
- # @request[:io] << data
69
- #
70
- # do NOT use Websocket#write (which writes the data directly, bypassing the protocol).
71
- #
72
- # We can also leverage the fact that the Http response can be used to send Websocket data.
73
- #
74
- # @response << data
75
- (@___ws_io ||= @request[:io]) << data
76
- end
77
-
78
- # Send messages directly to a specific Websocket.
79
- #
80
- # This implementation is limited to a single process on a single server.
81
- # Consider using Redis for a scalable implementation.
82
- def unicast id, data
83
- ::Iodine::Http::Websockets.unicast id, data
84
- end
85
- # Broadcast to all Websockets, except self.
86
- #
87
- # This implementation is limited to a single process on a single server.
88
- # Consider using Redis for a scalable implementation.
89
- def broadcast data
90
- ::Iodine::Http::Websockets.broadcast data, @request[:io]
91
- end
92
- # Closes the connection
93
- def close
94
- # @request[:io] contains the Websockets Protocol instance
95
- @request[:io].go_away
96
- end
97
- end
98
- end
99
- end
100
-
101
-
@@ -1,336 +0,0 @@
1
- module Iodine
2
- module Http
3
- class Websockets < ::Iodine::Protocol
4
- # continue to initialize the websocket protocol.
5
- def on_open
6
- @handler = @options[:handler]
7
- @ws_extentions = @options[:ext]
8
- @options[:request][:io] = self
9
- @parser = {body: String.new, stage: 0, step: 0, mask_key: [], len_bytes: []}
10
- set_timeout self.class.default_timeout
11
- @handler.on_open if @handler.respond_to? :on_open
12
- end
13
- # parse and handle messages.
14
- def on_message data
15
- extract_message StringIO.new(data)
16
- end
17
- # handle broadcasts.
18
- def on_broadcast data
19
- @locker.synchronize { @handler.on_broadcast(data) } if @handler.respond_to? :on_broadcast
20
- end
21
- # cleanup after closing.
22
- def on_close
23
- @handler.on_close if @handler.respond_to? :on_close
24
- if @ws_extentions
25
- @ws_extentions.each { |ex| ex.close }
26
- @ws_extentions.clear
27
- end
28
- end
29
-
30
- # a politer disconnection.
31
- def go_away
32
- write CLOSE_FRAME
33
- close
34
- end
35
-
36
- # a politer disconnection during shutdown.
37
- def on_shutdown
38
- @handler.on_shutdown if @handler.respond_to?(:on_shutdown)
39
- go_away
40
- end
41
-
42
- # allow Http responses to be used for sending Websocket data.
43
- def send_response response, finish = false
44
- body = response.extract_body
45
- send_data body.read
46
- end
47
- alias :stream_response :send_response
48
-
49
- # Sends the data as one (or more) Websocket frames.
50
- #
51
- # Use THIS method to send data using the Websocket protocol.
52
- # Using {Iodine::Protocol#write} will bypass the Websocket data framing and send the raw data, breaking the connection.
53
- def send_data data, op_code = nil, fin = true, ext = 0
54
- return false if !data || data.empty?
55
- return false if @io.closed?
56
- data = data.dup # needed?
57
- unless op_code # apply extenetions to the message as a whole
58
- op_code = (data.encoding == ::Encoding::UTF_8 ? 1 : 2)
59
- @ws_extentions.each { |ex| ext |= ex.edit_message data } if @ws_extentions
60
- end
61
- byte_size = data.bytesize
62
- if byte_size > (FRAME_SIZE_LIMIT+2)
63
- # sections = byte_size/FRAME_SIZE_LIMIT + (byte_size%FRAME_SIZE_LIMIT ? 1 : 0)
64
- send_data( data.slice!( 0...FRAME_SIZE_LIMIT ), op_code, data.empty?, ext) && (ext = op_code = 0) until data.empty?
65
- return true # avoid sending an empty frame.
66
- end
67
- @ws_extentions.each { |ex| ext |= ex.edit_frame data } if @ws_extentions
68
- header = ( (fin ? 0b10000000 : 0) | (op_code & 0b00001111) | ext).chr.force_encoding(::Encoding::ASCII_8BIT)
69
-
70
- if byte_size < 125
71
- header << byte_size.chr
72
- elsif byte_size.bit_length <= 16
73
- header << 126.chr
74
- header << [byte_size].pack('S>'.freeze)
75
- else
76
- header << 127.chr
77
- header << [byte_size].pack('Q>'.freeze)
78
- end
79
- write header
80
- write(data) && true
81
- end
82
- alias :<< :send_data
83
-
84
- # Sends a ping and calles the :on_ping callback (if exists).
85
- def ping
86
- write(PING_FRAME) && ( (@handler.respond_to?(:on_ping) && @handler.on_ping) || true)
87
- end
88
- # Sends an empty pong.
89
- def pong
90
- write PONG_FRAME
91
- end
92
-
93
- # Broadcasts data to ALL the websocket connections EXCEPT the once specified (if specified).
94
- #
95
- # Data broadcasted will be recived by the websocket handler it's #on_broadcast(ws) method (if exists).
96
- #
97
- # Accepts:
98
- #
99
- # data:: One object of data. Usually a Hash, Array, String or a JSON formatted object.
100
- # ignore_io (optional):: The IO to be ignored by the broadcast. Usually the broadcaster's IO.
101
- #
102
- def self.broadcast data, ignore_io = nil
103
- if ignore_io
104
- ig_id = ignore_io.object_id
105
- each {|io| Iodine.run io, data, &broadcast_proc unless io.object_id == ig_id}
106
- else
107
- each {|io| Iodine.run io, data, &broadcast_proc }
108
- end
109
- true
110
- end
111
-
112
- # Broadcasts the data to all the listening websockets, except self. See {::Iodine::Http::Websockets.broadcast}
113
- def broadcast data
114
- self.class.broadcast data, self
115
- end
116
-
117
- # Unicast data to a specific websocket connection (ONLY the connection specified).
118
- #
119
- # Data broadcasted will be recived by the websocket handler it's #on_broadcast(ws) method (if exists).
120
- # Accepts:
121
- # uuid:: the UUID of the websocket connection recipient.
122
- # data:: the data to be sent.
123
- #
124
- # @return [true, false] Returns true if the object was found and the unicast was sent (the task will be executed asynchronously once the unicast was sent).
125
- def self.unicast id, data
126
- return false unless id && data
127
- each {|io| next unless io.id == id; Iodine.run io, data, &broadcast_proc; return true}
128
- false
129
- end
130
- # @return [true, false] Unicasts the data to the requested connection. returns `true` if the requested connection id was found on this server. See {::Iodine::Http::Websockets.unicast}
131
- def unicast id, data
132
- self.class.unicast id, data
133
- end
134
-
135
- def self.handshake request, response, handler
136
- # review handshake (version, extentions)
137
- # should consider adopting the websocket gem for handshake and framing:
138
- # https://github.com/imanel/websocket-ruby
139
- # http://www.rubydoc.info/github/imanel/websocket-ruby
140
- return refuse response unless handler || handler == true
141
- io = request[:io]
142
- response.keep_alive = true
143
- response.status = 101
144
- response['upgrade'.freeze] = 'websocket'.freeze
145
- response['content-length'.freeze] = '0'.freeze
146
- response['connection'.freeze] = 'Upgrade'.freeze
147
- response['sec-websocket-version'.freeze] = '13'.freeze
148
- # Note that the client is only offering to use any advertised extensions
149
- # and MUST NOT use them unless the server indicates that it wishes to use the extension.
150
- ws_extentions = []
151
- ext = []
152
- request['sec-websocket-extensions'.freeze].to_s.split(/[\s]*[,][\s]*/.freeze).each {|ex| ex = ex.split(/[\s]*;[\s]*/.freeze); ( ( tmp = SUPPORTED_EXTENTIONS[ ex[0] ].call(ex[1..-1]) ) && (ws_extentions << tmp) && (ext << tmp.name) ) if SUPPORTED_EXTENTIONS[ ex[0] ] }
153
- ext.compact!
154
- if ext.any?
155
- response['sec-websocket-extensions'.freeze] = ext.join(', '.freeze)
156
- else
157
- ws_extentions = nil
158
- end
159
- response['sec-websocket-accept'.freeze] = Digest::SHA1.base64digest(request['sec-websocket-key'.freeze] + '258EAFA5-E914-47DA-95CA-C5AB0DC85B11'.freeze)
160
- response.session
161
- # Iodine.log "#{@request[:client_ip]} [#{Time.now.utc}] - #{@connection.object_id} Upgraded HTTP to WebSockets.\n"
162
- response.finish
163
- self.new(io.io, handler: handler, request: request, ext: ws_extentions)
164
- return true
165
- end
166
-
167
- # Gets the new connection timeout in seconds. Whenever this timeout is reached, a ping will be sent. Defaults to 40 (seconds).
168
- def self.default_timeout
169
- @default_timeout
170
- end
171
- # Sets the new connection timeout in seconds. Whenever this timeout is reached, a ping will be sent. Defaults to 40 (seconds).
172
- def self.default_timeout= val
173
- @default_timeout = val
174
- end
175
- # Sets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
176
- #
177
- # Although memory will be allocated for the latest TCP/IP frame,
178
- # this allows the websocket to disconnect if the incoming expected message size exceeds the allowed maximum size.
179
- #
180
- # If the message size limit is exceeded, the disconnection will be immidiate as an attack will be assumed. The protocol's normal disconnect sequesnce will be discarded.
181
- def self.message_size_limit=val
182
- @message_size_limit = val
183
- end
184
- # Gets the message byte size limit for a Websocket message. Defaults to 0 (no limit)
185
- def self.message_size_limit
186
- @message_size_limit ||= 0
187
- end
188
-
189
- protected
190
- FRAME_SIZE_LIMIT = 17_895_697
191
- SUPPORTED_EXTENTIONS = {}
192
- CLOSE_FRAME = "\x88\x00".freeze
193
- PONG_FRAME = "\x8A\x00".freeze
194
- PING_FRAME = "\x89\x00".freeze
195
- @default_timeout = 40
196
-
197
- def self.broadcast_proc
198
- @broadcast_proc ||= Proc.new {|io, data| io.on_broadcast data }
199
- end
200
-
201
- def self.refuse response
202
- response.status = 400
203
- response['sec-websocket-extensions'.freeze] = SUPPORTED_EXTENTIONS.keys.join(', '.freeze)
204
- response['sec-websocket-version'.freeze] = '13'.freeze
205
- false
206
- end
207
-
208
- # parse the message and send it to the handler
209
- #
210
- # test: frame = ["819249fcd3810b93b2fb69afb6e62c8af3e83adc94ee2ddd"].pack("H*").bytes; parser[:stage] = 0; parser = {}
211
- # accepts:
212
- # data:: an IO object (usually a StringIO object)
213
- def extract_message data
214
- parser = @parser
215
- until data.eof?
216
- if parser[:stage] == 0
217
- tmp = data.getbyte
218
- return unless tmp
219
- parser[:fin] = tmp[7] == 1
220
- parser[:rsv1] = tmp[6] == 1
221
- parser[:rsv2] = tmp[5] == 1
222
- parser[:rsv3] = tmp[4] == 1
223
- parser[:op_code] = tmp & 0b00001111
224
- parser[:p_op_code] ||= tmp & 0b00001111
225
- parser[:stage] += 1
226
- end
227
- if parser[:stage] == 1
228
- tmp = data.getbyte
229
- return unless tmp
230
- parser[:mask] = tmp[7]
231
- parser[:mask_key].clear
232
- parser[:len] = tmp & 0b01111111
233
- parser[:len_bytes].clear
234
- parser[:stage] += 1
235
- end
236
- if parser[:stage] == 2
237
- tmp = 0
238
- tmp = 2 if parser[:len] == 126
239
- tmp = 8 if parser[:len] == 127
240
- while parser[:len_bytes].length < tmp
241
- parser[:len_bytes] << data.getbyte
242
- return parser[:len_bytes].pop unless parser[:len_bytes].last
243
- end
244
- parser[:len] = merge_bytes( parser[:len_bytes] ) if tmp > 0
245
- parser[:step] = 0
246
- parser[:stage] += 1
247
- return false unless review_message_size
248
- end
249
- if parser[:stage] == 3 && parser[:mask] == 1
250
- until parser[:mask_key].length == 4
251
- parser[:mask_key] << data.getbyte
252
- return parser[:mask_key].pop unless parser[:mask_key].last
253
- end
254
- parser[:stage] += 1
255
- elsif parser[:stage] == 3 && parser[:mask] != 1
256
- parser[:stage] += 1
257
- end
258
- if parser[:stage] == 4
259
- if parser[:body].bytesize < parser[:len]
260
- tmp = data.read(parser[:len] - parser[:body].bytesize)
261
- return unless tmp
262
- parser[:body] << tmp
263
- end
264
- if parser[:body].bytesize >= parser[:len]
265
- tmp = -1
266
- parser[:body] = parser[:body].bytes.map! {|b| (b ^ parser[:mask_key][tmp = (tmp + 1)%4]) } .pack('C*'.freeze) if parser[:mask] == 1
267
- # parser[:body].bytesize.times {|i| parser[:body][i] = (parser[:body][i].ord ^ parser[:mask_key][i % 4]).chr} if parser[:mask] == 1
268
- parser[:stage] = 99
269
- end
270
- end
271
- complete_frame if parser[:stage] == 99
272
- end
273
- end
274
-
275
- # takes and Array of bytes and combines them to an int(16 Bit), 32Bit or 64Bit number
276
- def merge_bytes bytes
277
- return 0 unless bytes.any?
278
- return bytes.pop if bytes.length == 1
279
- bytes.pop ^ (merge_bytes(bytes) << 8)
280
- end
281
-
282
- # handles the completed frame and sends a message to the handler once all the data has arrived.
283
- def complete_frame
284
- parser = @parser
285
- @ws_extentions.each {|ex| ex.parse_frame(parser) } if @ws_extentions
286
-
287
- case parser[:op_code]
288
- when 9 # ping
289
- # handle parser[:op_code] == 9 (ping)
290
- ::Iodine.run { send_data parser[:body], 10 }
291
- parser[:p_op_code] = nil if parser[:p_op_code] == 9
292
- when 10 #pong
293
- # handle parser[:op_code] == 10 (pong)
294
- parser[:p_op_code] = nil if parser[:p_op_code] == 10
295
- when 8 # close
296
- # handle parser[:op_code] == 8 (close)
297
- write( CLOSE_FRAME )
298
- close
299
- parser[:p_op_code] = nil if parser[:p_op_code] == 8
300
- else
301
- parser[:message] ? ((parser[:message] << parser[:body]) && parser[:body].clear) : ((parser[:message] = parser[:body]) && parser[:body] = String.new)
302
- # handle parser[:op_code] == 0 / fin == false (continue a frame that hasn't ended yet)
303
- if parser[:fin]
304
- @ws_extentions.each {|ex| ex.parse_message(parser) } if @ws_extentions
305
- Iodine::Http::Request.make_utf8! parser[:message] if parser[:p_op_code] == 1
306
- @handler.on_message parser[:message]
307
- parser[:message] = nil
308
- parser[:p_op_code] = nil
309
- end
310
- end
311
- parser[:stage] = 0
312
- parser[:body].clear
313
- parser[:step] = 0
314
- parser[:mask_key].clear
315
- parser[:p_op_code] = nil
316
- end
317
- #reviews the message size and closes the connection if expected message size is over the allowed limit.
318
- def review_message_size
319
- if ( self.class.message_size_limit.to_i > 0 ) && ( ( @parser[:len] + (@parser[:message] ? @parser[:message].bytesize : 0) ) > self.class.message_size_limit.to_i )
320
- close
321
- @parser.delete :message
322
- @parser[:step] = 0
323
- @parser[:body].clear
324
- @parser[:mask_key].clear
325
- Iodine.warn "Websocket message above limit's set - closing connection."
326
- return false
327
- end
328
- true
329
- end
330
-
331
-
332
- end
333
- end
334
- end
335
-
336
-
data/lib/iodine/io.rb DELETED
@@ -1,56 +0,0 @@
1
- module Iodine
2
-
3
- public
4
-
5
- # @return [Time] Gets the last time at which the IO Reactor was last active (last "tick").
6
- def time
7
- @time
8
- end
9
- # Replaces (or creates) an IO's protocol object.
10
- #
11
- # Accepts 2 arguments, in the following order:
12
- #
13
- # io:: the raw IO object.
14
- # protocol:: a protocol instance - should be an instance of a class inheriting from {Iodine::Protocol}. type will NOT be checked - but Iodine could break if there is a type mismatch.
15
- # @return [Protocol]
16
- def switch_protocol *args
17
- @io_in << args
18
- args[1]
19
- end
20
-
21
- # @return [Array] Returns an Array with all the currently active connection's Protocol instances.
22
- def to_a
23
- @ios.values
24
- end
25
-
26
-
27
- protected
28
-
29
- # internal helper methods and classes.
30
- module Base
31
- # the server listener Protocol.
32
- class Listener < ::Iodine::Protocol
33
- def on_open
34
- @protocol = Iodine.protocol
35
- @ssl = Iodine.ssl
36
- @accept_proc = @protocol.method(:accept)
37
- end
38
- def call
39
- begin
40
- n_io = nil
41
- loop do
42
- n_io = @io.accept_nonblock
43
- # @protocol.accept(n_io, @ssl)
44
- Iodine.run n_io, @ssl, &(@accept_proc)
45
- end
46
- rescue Errno::EWOULDBLOCK => e
47
-
48
- rescue => e
49
- n_io.close if n_io && !n_io.closed?
50
- @stop = true
51
- raise e
52
- end
53
- end
54
- end
55
- end
56
- end