eventmachine 1.2.0.1-x86-mingw32 → 1.2.1-x86-mingw32
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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +12 -0
- data/README.md +25 -23
- data/ext/ed.cpp +40 -65
- data/ext/ed.h +23 -8
- data/ext/em.cpp +23 -12
- data/ext/em.h +1 -1
- data/ext/rubymain.cpp +19 -15
- data/java/src/com/rubyeventmachine/EmReactor.java +18 -2
- data/lib/1.9/fastfilereaderext.so +0 -0
- data/lib/1.9/rubyeventmachine.so +0 -0
- data/lib/2.0/fastfilereaderext.so +0 -0
- data/lib/2.0/rubyeventmachine.so +0 -0
- data/lib/2.1/fastfilereaderext.so +0 -0
- data/lib/2.1/rubyeventmachine.so +0 -0
- data/lib/2.2/fastfilereaderext.so +0 -0
- data/lib/2.2/rubyeventmachine.so +0 -0
- data/lib/2.3/fastfilereaderext.so +0 -0
- data/lib/2.3/rubyeventmachine.so +0 -0
- data/lib/em/pool.rb +35 -35
- data/lib/em/protocols/linetext2.rb +18 -5
- data/lib/em/pure_ruby.rb +290 -52
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +6 -0
- data/lib/jeventmachine.rb +2 -0
- data/rakelib/test_pure.rake +13 -0
- data/tests/em_test_helper.rb +3 -0
- data/tests/test_basic.rb +32 -0
- data/tests/test_ltp2.rb +24 -0
- data/tests/test_pure.rb +51 -0
- data/tests/test_ssl_dhparam.rb +2 -1
- data/tests/test_ssl_ecdh_curve.rb +2 -1
- data/tests/test_ssl_extensions.rb +1 -1
- data/tests/test_ssl_protocols.rb +3 -3
- data/tests/test_ssl_verify.rb +2 -0
- metadata +3 -2
@@ -521,11 +521,27 @@ public class EmReactor {
|
|
521
521
|
}
|
522
522
|
|
523
523
|
public Object[] getPeerName (long sig) {
|
524
|
-
|
524
|
+
EventableChannel channel = Connections.get(sig);
|
525
|
+
if (channel != null) {
|
526
|
+
return Connections.get(sig).getPeerName();
|
527
|
+
}
|
528
|
+
else {
|
529
|
+
ServerSocketChannel acceptor = Acceptors.get(sig);
|
530
|
+
return new Object[] { acceptor.socket().getLocalPort(),
|
531
|
+
acceptor.socket().getInetAddress().getHostAddress() };
|
532
|
+
}
|
525
533
|
}
|
526
534
|
|
527
535
|
public Object[] getSockName (long sig) {
|
528
|
-
|
536
|
+
EventableChannel channel = Connections.get(sig);
|
537
|
+
if (channel != null) {
|
538
|
+
return Connections.get(sig).getSockName();
|
539
|
+
}
|
540
|
+
else {
|
541
|
+
ServerSocketChannel acceptor = Acceptors.get(sig);
|
542
|
+
return new Object[] { acceptor.socket().getLocalPort(),
|
543
|
+
acceptor.socket().getInetAddress().getHostAddress() };
|
544
|
+
}
|
529
545
|
}
|
530
546
|
|
531
547
|
public long attachChannel (SocketChannel sc, boolean watch_mode) {
|
Binary file
|
data/lib/1.9/rubyeventmachine.so
CHANGED
Binary file
|
Binary file
|
data/lib/2.0/rubyeventmachine.so
CHANGED
Binary file
|
Binary file
|
data/lib/2.1/rubyeventmachine.so
CHANGED
Binary file
|
Binary file
|
data/lib/2.2/rubyeventmachine.so
CHANGED
Binary file
|
Binary file
|
data/lib/2.3/rubyeventmachine.so
CHANGED
Binary file
|
data/lib/em/pool.rb
CHANGED
@@ -1,41 +1,41 @@
|
|
1
1
|
module EventMachine
|
2
|
-
# = EventMachine::Pool
|
3
|
-
#
|
4
2
|
# A simple async resource pool based on a resource and work queue. Resources
|
5
3
|
# are enqueued and work waits for resources to become available.
|
6
4
|
#
|
7
|
-
#
|
5
|
+
# @example
|
6
|
+
# require 'em-http-request'
|
7
|
+
#
|
8
|
+
# EM.run do
|
9
|
+
# pool = EM::Pool.new
|
10
|
+
# spawn = lambda { pool.add EM::HttpRequest.new('http://example.org') }
|
11
|
+
# 10.times { spawn[] }
|
12
|
+
# done, scheduled = 0, 0
|
13
|
+
#
|
14
|
+
# check = lambda do
|
15
|
+
# done += 1
|
16
|
+
# if done >= scheduled
|
17
|
+
# EM.stop
|
18
|
+
# end
|
19
|
+
# end
|
20
|
+
#
|
21
|
+
# pool.on_error { |conn| spawn[] }
|
22
|
+
#
|
23
|
+
# 100.times do |i|
|
24
|
+
# scheduled += 1
|
25
|
+
# pool.perform do |conn|
|
26
|
+
# req = conn.get :path => '/', :keepalive => true
|
27
|
+
#
|
28
|
+
# req.callback do
|
29
|
+
# p [:success, conn.object_id, i, req.response.size]
|
30
|
+
# check[]
|
31
|
+
# end
|
32
|
+
#
|
33
|
+
# req.errback { check[] }
|
8
34
|
#
|
9
|
-
#
|
10
|
-
#
|
11
|
-
#
|
12
|
-
#
|
13
|
-
# done, scheduled = 0, 0
|
14
|
-
#
|
15
|
-
# check = lambda do
|
16
|
-
# done += 1
|
17
|
-
# if done >= scheduled
|
18
|
-
# EM.stop
|
19
|
-
# end
|
20
|
-
# end
|
21
|
-
#
|
22
|
-
# pool.on_error { |conn| spawn[] }
|
23
|
-
#
|
24
|
-
# 100.times do
|
25
|
-
# pool.perform do |conn|
|
26
|
-
# req = conn.get :path => '/', :keepalive => true
|
27
|
-
#
|
28
|
-
# req.callback do
|
29
|
-
# p [:success, conn.object_id, i, req.response.size]
|
30
|
-
# check[]
|
31
|
-
# end
|
32
|
-
#
|
33
|
-
# req.errback { check[] }
|
34
|
-
#
|
35
|
-
# req
|
36
|
-
# end
|
37
|
-
# end
|
38
|
-
# end
|
35
|
+
# req
|
36
|
+
# end
|
37
|
+
# end
|
38
|
+
# end
|
39
39
|
#
|
40
40
|
# Resources are expected to be controlled by an object responding to a
|
41
41
|
# deferrable/completion style API with callback and errback blocks.
|
@@ -64,8 +64,8 @@ module EventMachine
|
|
64
64
|
# example use case is periodic statistics collection against a set of
|
65
65
|
# connection resources.
|
66
66
|
#
|
67
|
-
#
|
68
|
-
#
|
67
|
+
# @example
|
68
|
+
# pool.contents.inject(0) { |sum, connection| connection.num_bytes }
|
69
69
|
def contents
|
70
70
|
@contents.dup
|
71
71
|
end
|
@@ -56,7 +56,14 @@ module EventMachine
|
|
56
56
|
|
57
57
|
while remaining_data.length > 0
|
58
58
|
if @lt2_mode == :lines
|
59
|
-
|
59
|
+
delimiter_string = case @lt2_delimiter
|
60
|
+
when Regexp
|
61
|
+
remaining_data.slice(@lt2_delimiter)
|
62
|
+
else
|
63
|
+
@lt2_delimiter
|
64
|
+
end
|
65
|
+
ix = remaining_data.index(delimiter_string) if delimiter_string
|
66
|
+
if ix
|
60
67
|
@lt2_linebuffer << remaining_data[0...ix]
|
61
68
|
ln = @lt2_linebuffer.join
|
62
69
|
@lt2_linebuffer.clear
|
@@ -64,7 +71,7 @@ module EventMachine
|
|
64
71
|
ln.chomp!
|
65
72
|
end
|
66
73
|
receive_line ln
|
67
|
-
remaining_data = remaining_data[(ix
|
74
|
+
remaining_data = remaining_data[(ix+delimiter_string.length)..-1]
|
68
75
|
else
|
69
76
|
@lt2_linebuffer << remaining_data
|
70
77
|
remaining_data = ""
|
@@ -101,9 +108,16 @@ module EventMachine
|
|
101
108
|
end
|
102
109
|
end
|
103
110
|
|
104
|
-
|
111
|
+
# The line delimiter may be a regular expression or a string. Anything
|
112
|
+
# passed to set_delimiter other than a regular expression will be
|
113
|
+
# converted to a string.
|
105
114
|
def set_delimiter delim
|
106
|
-
@lt2_delimiter = delim
|
115
|
+
@lt2_delimiter = case delim
|
116
|
+
when Regexp
|
117
|
+
delim
|
118
|
+
else
|
119
|
+
delim.to_s
|
120
|
+
end
|
107
121
|
end
|
108
122
|
|
109
123
|
# Called internally but also exposed to user code, for the case in which
|
@@ -163,4 +177,3 @@ module EventMachine
|
|
163
177
|
end
|
164
178
|
end
|
165
179
|
end
|
166
|
-
|
data/lib/em/pure_ruby.rb
CHANGED
@@ -33,6 +33,88 @@ require 'forwardable'
|
|
33
33
|
require 'socket'
|
34
34
|
require 'fcntl'
|
35
35
|
require 'set'
|
36
|
+
require 'openssl'
|
37
|
+
|
38
|
+
module EventMachine
|
39
|
+
# @private
|
40
|
+
class Error < Exception; end
|
41
|
+
# @private
|
42
|
+
class UnknownTimerFired < RuntimeError; end
|
43
|
+
# @private
|
44
|
+
class Unsupported < RuntimeError; end
|
45
|
+
# @private
|
46
|
+
class ConnectionError < RuntimeError; end
|
47
|
+
# @private
|
48
|
+
class ConnectionNotBound < RuntimeError; end
|
49
|
+
|
50
|
+
# Older versions of Ruby may not provide the SSLErrorWaitReadable
|
51
|
+
# OpenSSL class. Create an error class to act as a "proxy".
|
52
|
+
if defined?(OpenSSL::SSL::SSLErrorWaitReadable)
|
53
|
+
SSLConnectionWaitReadable = OpenSSL::SSL::SSLErrorWaitReadable
|
54
|
+
else
|
55
|
+
SSLConnectionWaitReadable = IO::WaitReadable
|
56
|
+
end
|
57
|
+
|
58
|
+
# Older versions of Ruby may not provide the SSLErrorWaitWritable
|
59
|
+
# OpenSSL class. Create an error class to act as a "proxy".
|
60
|
+
if defined?(OpenSSL::SSL::SSLErrorWaitWritable)
|
61
|
+
SSLConnectionWaitWritable = OpenSSL::SSL::SSLErrorWaitWritable
|
62
|
+
else
|
63
|
+
SSLConnectionWaitWritable = IO::WaitWritable
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
module EventMachine
|
68
|
+
class CertificateCreator
|
69
|
+
attr_reader :cert, :key
|
70
|
+
|
71
|
+
def initialize
|
72
|
+
@key = OpenSSL::PKey::RSA.new(1024)
|
73
|
+
public_key = @key.public_key
|
74
|
+
subject = "/C=EventMachine/O=EventMachine/OU=EventMachine/CN=EventMachine"
|
75
|
+
@cert = OpenSSL::X509::Certificate.new
|
76
|
+
@cert.subject = @cert.issuer = OpenSSL::X509::Name.parse(subject)
|
77
|
+
@cert.not_before = Time.now
|
78
|
+
@cert.not_after = Time.now + 365 * 24 * 60 * 60
|
79
|
+
@cert.public_key = public_key
|
80
|
+
@cert.serial = 0x0
|
81
|
+
@cert.version = 2
|
82
|
+
factory = OpenSSL::X509::ExtensionFactory.new
|
83
|
+
factory.subject_certificate = @cert
|
84
|
+
factory.issuer_certificate = @cert
|
85
|
+
@cert.extensions = [
|
86
|
+
factory.create_extension("basicConstraints","CA:TRUE", true),
|
87
|
+
factory.create_extension("subjectKeyIdentifier", "hash")
|
88
|
+
]
|
89
|
+
@cert.add_extension factory.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
|
90
|
+
@cert.sign(@key, OpenSSL::Digest::SHA1.new)
|
91
|
+
end
|
92
|
+
end
|
93
|
+
|
94
|
+
# @private
|
95
|
+
DefaultCertificate = CertificateCreator.new
|
96
|
+
|
97
|
+
# @private
|
98
|
+
DefaultDHKey1024 = OpenSSL::PKey::DH.new <<-_end_of_pem_
|
99
|
+
-----BEGIN DH PARAMETERS-----
|
100
|
+
MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ
|
101
|
+
AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR
|
102
|
+
T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC
|
103
|
+
-----END DH PARAMETERS-----
|
104
|
+
_end_of_pem_
|
105
|
+
|
106
|
+
# @private
|
107
|
+
DefaultDHKey2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
|
108
|
+
-----BEGIN DH PARAMETERS-----
|
109
|
+
MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY
|
110
|
+
JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab
|
111
|
+
VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6
|
112
|
+
YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
|
113
|
+
1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD
|
114
|
+
7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg==
|
115
|
+
-----END DH PARAMETERS-----
|
116
|
+
_end_of_pem_
|
117
|
+
end
|
36
118
|
|
37
119
|
# @private
|
38
120
|
module EventMachine
|
@@ -92,14 +174,10 @@ module EventMachine
|
|
92
174
|
selectable.send_data data
|
93
175
|
end
|
94
176
|
|
95
|
-
|
96
|
-
# The extension version does NOT raise any kind of an error if an attempt is made
|
97
|
-
# to close a non-existent connection. Not sure whether we should. For now, we'll
|
98
|
-
# raise an error here in that case.
|
99
177
|
# @private
|
100
178
|
def close_connection target, after_writing
|
101
|
-
selectable = Reactor.instance.get_selectable( target )
|
102
|
-
selectable.schedule_close after_writing
|
179
|
+
selectable = Reactor.instance.get_selectable( target )
|
180
|
+
selectable.schedule_close after_writing if selectable
|
103
181
|
end
|
104
182
|
|
105
183
|
# @private
|
@@ -163,10 +241,127 @@ module EventMachine
|
|
163
241
|
def epoll
|
164
242
|
end
|
165
243
|
|
166
|
-
# This method is not implemented for pure-Ruby implementation
|
167
244
|
# @private
|
168
245
|
def ssl?
|
169
|
-
|
246
|
+
true
|
247
|
+
end
|
248
|
+
|
249
|
+
def tls_parm_set?(parm)
|
250
|
+
!(parm.nil? || parm.empty?)
|
251
|
+
end
|
252
|
+
|
253
|
+
# This method takes a series of positional arguments for specifying such
|
254
|
+
# things as private keys and certificate chains. It's expected that the
|
255
|
+
# parameter list will grow as we add more supported features. ALL of these
|
256
|
+
# parameters are optional, and can be specified as empty or nil strings.
|
257
|
+
# @private
|
258
|
+
def set_tls_parms signature, priv_key, cert_chain, verify_peer, fail_if_no_peer_cert, sni_hostname, cipher_list, ecdh_curve, dhparam, protocols_bitmask
|
259
|
+
bitmask = protocols_bitmask
|
260
|
+
ssl_options = OpenSSL::SSL::OP_ALL
|
261
|
+
ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2) && EM_PROTO_SSLv2 & bitmask == 0
|
262
|
+
ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3) && EM_PROTO_SSLv3 & bitmask == 0
|
263
|
+
ssl_options |= OpenSSL::SSL::OP_NO_TLSv1 if defined?(OpenSSL::SSL::OP_NO_TLSv1) && EM_PROTO_TLSv1 & bitmask == 0
|
264
|
+
ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_1 if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) && EM_PROTO_TLSv1_1 & bitmask == 0
|
265
|
+
ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_2 if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) && EM_PROTO_TLSv1_2 & bitmask == 0
|
266
|
+
@tls_parms ||= {}
|
267
|
+
@tls_parms[signature] = {
|
268
|
+
:verify_peer => verify_peer,
|
269
|
+
:fail_if_no_peer_cert => fail_if_no_peer_cert,
|
270
|
+
:ssl_options => ssl_options
|
271
|
+
}
|
272
|
+
@tls_parms[signature][:priv_key] = File.read(priv_key) if tls_parm_set?(priv_key)
|
273
|
+
@tls_parms[signature][:cert_chain] = File.read(cert_chain) if tls_parm_set?(cert_chain)
|
274
|
+
@tls_parms[signature][:sni_hostname] = sni_hostname if tls_parm_set?(sni_hostname)
|
275
|
+
@tls_parms[signature][:cipher_list] = cipher_list.gsub(/,\s*/, ':') if tls_parm_set?(cipher_list)
|
276
|
+
@tls_parms[signature][:dhparam] = File.read(dhparam) if tls_parm_set?(dhparam)
|
277
|
+
@tls_parms[signature][:ecdh_curve] = ecdh_curve if tls_parm_set?(ecdh_curve)
|
278
|
+
end
|
279
|
+
|
280
|
+
def start_tls signature
|
281
|
+
selectable = Reactor.instance.get_selectable(signature) or raise "unknown io selectable for start_tls"
|
282
|
+
tls_parms = @tls_parms[signature]
|
283
|
+
ctx = OpenSSL::SSL::SSLContext.new
|
284
|
+
ctx.options = tls_parms[:ssl_options]
|
285
|
+
ctx.cert = DefaultCertificate.cert
|
286
|
+
ctx.key = DefaultCertificate.key
|
287
|
+
ctx.cert_store = OpenSSL::X509::Store.new
|
288
|
+
ctx.cert_store.set_default_paths
|
289
|
+
ctx.cert = OpenSSL::X509::Certificate.new(tls_parms[:cert_chain]) if tls_parms[:cert_chain]
|
290
|
+
ctx.key = OpenSSL::PKey::RSA.new(tls_parms[:priv_key]) if tls_parms[:priv_key]
|
291
|
+
verify_mode = OpenSSL::SSL::VERIFY_NONE
|
292
|
+
if tls_parms[:verify_peer]
|
293
|
+
verify_mode |= OpenSSL::SSL::VERIFY_PEER
|
294
|
+
end
|
295
|
+
if tls_parms[:fail_if_no_peer_cert]
|
296
|
+
verify_mode |= OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
|
297
|
+
end
|
298
|
+
ctx.verify_mode = verify_mode
|
299
|
+
ctx.servername_cb = Proc.new do |_, server_name|
|
300
|
+
tls_parms[:server_name] = server_name
|
301
|
+
nil
|
302
|
+
end
|
303
|
+
ctx.ciphers = tls_parms[:cipher_list] if tls_parms[:cipher_list]
|
304
|
+
if selectable.is_server
|
305
|
+
ctx.tmp_dh_callback = Proc.new do |_, _, key_length|
|
306
|
+
if tls_parms[:dhparam]
|
307
|
+
OpenSSL::PKey::DH.new(tls_parms[:dhparam])
|
308
|
+
else
|
309
|
+
case key_length
|
310
|
+
when 1024 then DefaultDHKey1024
|
311
|
+
when 2048 then DefaultDHKey2048
|
312
|
+
else
|
313
|
+
nil
|
314
|
+
end
|
315
|
+
end
|
316
|
+
end
|
317
|
+
if tls_parms[:ecdh_curve] && ctx.respond_to?(:tmp_ecdh_callback)
|
318
|
+
ctx.tmp_ecdh_callback = Proc.new do
|
319
|
+
OpenSSL::PKey::EC.new(tls_parms[:ecdh_curve])
|
320
|
+
end
|
321
|
+
end
|
322
|
+
end
|
323
|
+
ssl_io = OpenSSL::SSL::SSLSocket.new(selectable, ctx)
|
324
|
+
ssl_io.sync_close = true
|
325
|
+
if tls_parms[:sni_hostname]
|
326
|
+
ssl_io.hostname = tls_parms[:sni_hostname] if ssl_io.respond_to?(:hostname=)
|
327
|
+
end
|
328
|
+
begin
|
329
|
+
selectable.is_server ? ssl_io.accept_nonblock : ssl_io.connect_nonblock
|
330
|
+
rescue; end
|
331
|
+
selectable.io = ssl_io
|
332
|
+
end
|
333
|
+
|
334
|
+
def get_peer_cert signature
|
335
|
+
selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_peer_cert target"
|
336
|
+
if selectable.io.respond_to?(:peer_cert) && selectable.io.peer_cert
|
337
|
+
selectable.io.peer_cert.to_pem
|
338
|
+
else
|
339
|
+
nil
|
340
|
+
end
|
341
|
+
end
|
342
|
+
|
343
|
+
def get_cipher_name signature
|
344
|
+
selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_name target"
|
345
|
+
selectable.io.respond_to?(:cipher) ? selectable.io.cipher[0] : nil
|
346
|
+
end
|
347
|
+
|
348
|
+
def get_cipher_protocol signature
|
349
|
+
selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_protocol target"
|
350
|
+
selectable.io.respond_to?(:cipher) ? selectable.io.cipher[1] : nil
|
351
|
+
end
|
352
|
+
|
353
|
+
def get_cipher_bits signature
|
354
|
+
selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_bits target"
|
355
|
+
selectable.io.respond_to?(:cipher) ? selectable.io.cipher[2] : nil
|
356
|
+
end
|
357
|
+
|
358
|
+
def get_sni_hostname signature
|
359
|
+
@tls_parms ||= {}
|
360
|
+
if @tls_parms[signature]
|
361
|
+
@tls_parms[signature][:server_name]
|
362
|
+
else
|
363
|
+
nil
|
364
|
+
end
|
170
365
|
end
|
171
366
|
|
172
367
|
# This method is a no-op in the pure-Ruby implementation. We simply return Ruby's built-in
|
@@ -184,13 +379,13 @@ module EventMachine
|
|
184
379
|
|
185
380
|
# @private
|
186
381
|
def get_sock_opt signature, level, optname
|
187
|
-
selectable = Reactor.instance.get_selectable( signature ) or raise "unknown
|
382
|
+
selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_sock_opt target"
|
188
383
|
selectable.getsockopt level, optname
|
189
384
|
end
|
190
385
|
|
191
386
|
# @private
|
192
387
|
def set_sock_opt signature, level, optname, optval
|
193
|
-
selectable = Reactor.instance.get_selectable( signature ) or raise "unknown
|
388
|
+
selectable = Reactor.instance.get_selectable( signature ) or raise "unknown set_sock_opt target"
|
194
389
|
selectable.setsockopt level, optname, optval
|
195
390
|
end
|
196
391
|
|
@@ -223,13 +418,13 @@ module EventMachine
|
|
223
418
|
r = Reactor.instance.get_selectable( sig ) or raise "unknown set_comm_inactivity_timeout target"
|
224
419
|
r.set_inactivity_timeout tm
|
225
420
|
end
|
226
|
-
end
|
227
|
-
end
|
228
|
-
|
229
421
|
|
230
|
-
|
231
|
-
|
232
|
-
|
422
|
+
# @private
|
423
|
+
def set_pending_connect_timeout sig, tm
|
424
|
+
# Needs to be implemented. Currently a no-op stub to allow
|
425
|
+
# certain software to operate with the EM pure-ruby.
|
426
|
+
end
|
427
|
+
end
|
233
428
|
end
|
234
429
|
|
235
430
|
module EventMachine
|
@@ -269,6 +464,24 @@ module EventMachine
|
|
269
464
|
ConnectionCompleted = 104
|
270
465
|
# @private
|
271
466
|
LoopbreakSignalled = 105
|
467
|
+
# @private
|
468
|
+
ConnectionNotifyReadable = 106
|
469
|
+
# @private
|
470
|
+
ConnectionNotifyWritable = 107
|
471
|
+
# @private
|
472
|
+
SslHandshakeCompleted = 108
|
473
|
+
# @private
|
474
|
+
SslVerify = 109
|
475
|
+
# @private
|
476
|
+
EM_PROTO_SSLv2 = 2
|
477
|
+
# @private
|
478
|
+
EM_PROTO_SSLv3 = 4
|
479
|
+
# @private
|
480
|
+
EM_PROTO_TLSv1 = 8
|
481
|
+
# @private
|
482
|
+
EM_PROTO_TLSv1_1 = 16
|
483
|
+
# @private
|
484
|
+
EM_PROTO_TLSv1_2 = 32
|
272
485
|
end
|
273
486
|
|
274
487
|
module EventMachine
|
@@ -376,6 +589,9 @@ module EventMachine
|
|
376
589
|
@selectables.delete_if {|k,io|
|
377
590
|
if io.close_scheduled?
|
378
591
|
io.close
|
592
|
+
begin
|
593
|
+
EventMachine::event_callback io.uuid, ConnectionUnbound, nil
|
594
|
+
rescue ConnectionNotBound; end
|
379
595
|
true
|
380
596
|
end
|
381
597
|
}
|
@@ -414,8 +630,9 @@ module EventMachine
|
|
414
630
|
end
|
415
631
|
|
416
632
|
def signal_loopbreak
|
417
|
-
|
418
|
-
|
633
|
+
begin
|
634
|
+
@loopbreak_writer.send('+',0,"127.0.0.1",@loopbreak_port) if @loopbreak_writer
|
635
|
+
rescue IOError; end
|
419
636
|
end
|
420
637
|
|
421
638
|
def set_timer_quantum interval_in_seconds
|
@@ -435,6 +652,8 @@ class IO
|
|
435
652
|
def_delegator :@my_selectable, :eventable_read
|
436
653
|
def_delegator :@my_selectable, :eventable_write
|
437
654
|
def_delegator :@my_selectable, :uuid
|
655
|
+
def_delegator :@my_selectable, :is_server
|
656
|
+
def_delegator :@my_selectable, :is_server=
|
438
657
|
def_delegator :@my_selectable, :send_data
|
439
658
|
def_delegator :@my_selectable, :schedule_close
|
440
659
|
def_delegator :@my_selectable, :get_peername
|
@@ -442,17 +661,21 @@ class IO
|
|
442
661
|
def_delegator :@my_selectable, :get_outbound_data_size
|
443
662
|
def_delegator :@my_selectable, :set_inactivity_timeout
|
444
663
|
def_delegator :@my_selectable, :heartbeat
|
664
|
+
def_delegator :@my_selectable, :io
|
665
|
+
def_delegator :@my_selectable, :io=
|
445
666
|
end
|
446
667
|
|
447
668
|
module EventMachine
|
448
669
|
# @private
|
449
670
|
class Selectable
|
450
671
|
|
451
|
-
|
672
|
+
attr_accessor :io, :is_server
|
673
|
+
attr_reader :uuid
|
452
674
|
|
453
675
|
def initialize io
|
454
|
-
@uuid = UuidGenerator.generate
|
455
676
|
@io = io
|
677
|
+
@uuid = UuidGenerator.generate
|
678
|
+
@is_server = false
|
456
679
|
@last_activity = Reactor.instance.current_loop_time
|
457
680
|
|
458
681
|
if defined?(Fcntl::F_GETFL)
|
@@ -499,6 +722,14 @@ module EventMachine
|
|
499
722
|
|
500
723
|
def heartbeat
|
501
724
|
end
|
725
|
+
|
726
|
+
def schedule_close(after_writing=false)
|
727
|
+
if after_writing
|
728
|
+
@close_requested = true
|
729
|
+
else
|
730
|
+
@close_scheduled = true
|
731
|
+
end
|
732
|
+
end
|
502
733
|
end
|
503
734
|
|
504
735
|
end
|
@@ -552,9 +783,9 @@ module EventMachine
|
|
552
783
|
data = io.sysread(4096)
|
553
784
|
EventMachine::event_callback uuid, ConnectionData, data
|
554
785
|
end
|
555
|
-
rescue Errno::EAGAIN, Errno::EWOULDBLOCK
|
786
|
+
rescue Errno::EAGAIN, Errno::EWOULDBLOCK, SSLConnectionWaitReadable
|
556
787
|
# no-op
|
557
|
-
rescue Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError
|
788
|
+
rescue Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError, Errno::EPIPE, OpenSSL::SSL::SSLError
|
558
789
|
@close_scheduled = true
|
559
790
|
EventMachine::event_callback uuid, ConnectionUnbound, nil
|
560
791
|
end
|
@@ -589,9 +820,10 @@ module EventMachine
|
|
589
820
|
@outbound_q.unshift data[w..-1]
|
590
821
|
break
|
591
822
|
end
|
592
|
-
rescue Errno::EAGAIN
|
823
|
+
rescue Errno::EAGAIN, SSLConnectionWaitReadable, SSLConnectionWaitWritable
|
593
824
|
@outbound_q.unshift data
|
594
|
-
|
825
|
+
break
|
826
|
+
rescue EOFError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EPIPE, OpenSSL::SSL::SSLError
|
595
827
|
@close_scheduled = true
|
596
828
|
@outbound_q.clear
|
597
829
|
end
|
@@ -607,16 +839,6 @@ module EventMachine
|
|
607
839
|
end
|
608
840
|
end
|
609
841
|
|
610
|
-
# #schedule_close
|
611
|
-
# The application wants to close the connection.
|
612
|
-
def schedule_close after_writing
|
613
|
-
if after_writing
|
614
|
-
@close_requested = true
|
615
|
-
else
|
616
|
-
@close_scheduled = true
|
617
|
-
end
|
618
|
-
end
|
619
|
-
|
620
842
|
# #get_peername
|
621
843
|
# This is defined in the normal way on connected stream objects.
|
622
844
|
# Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants.
|
@@ -657,39 +879,58 @@ module EventMachine
|
|
657
879
|
# TODO, this assumes a current Ruby snapshot.
|
658
880
|
# We need to degrade to a nonblocking connect otherwise.
|
659
881
|
sd.connect_nonblock( Socket.pack_sockaddr_in( port, host ))
|
660
|
-
rescue Errno::EINPROGRESS
|
882
|
+
rescue Errno::ECONNREFUSED, Errno::EINPROGRESS
|
661
883
|
end
|
662
884
|
EvmaTCPClient.new sd
|
663
885
|
end
|
664
886
|
|
665
|
-
|
666
887
|
def initialize io
|
667
888
|
super
|
668
889
|
@pending = true
|
890
|
+
@handshake_complete = false
|
669
891
|
end
|
670
892
|
|
671
|
-
|
672
|
-
|
673
|
-
|
893
|
+
def ready?
|
894
|
+
if RUBY_PLATFORM =~ /linux/
|
895
|
+
io.getsockopt(Socket::SOL_TCP, Socket::TCP_INFO).unpack("i").first == 1 # TCP_ESTABLISHED
|
896
|
+
else
|
897
|
+
io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first == 0 # NO ERROR
|
898
|
+
end
|
674
899
|
end
|
675
900
|
|
676
|
-
def
|
677
|
-
|
901
|
+
def handshake_complete?
|
902
|
+
if !@handshake_complete && io.respond_to?(:state)
|
903
|
+
if io.state =~ /^SSLOK/
|
904
|
+
@handshake_complete = true
|
905
|
+
EventMachine::event_callback uuid, SslHandshakeCompleted, ""
|
906
|
+
EventMachine::event_callback uuid, SslVerify, io.peer_cert.to_pem if io.peer_cert
|
907
|
+
end
|
908
|
+
else
|
909
|
+
@handshake_complete = true
|
910
|
+
end
|
911
|
+
@handshake_complete
|
678
912
|
end
|
679
913
|
|
680
|
-
def
|
914
|
+
def pending?
|
915
|
+
handshake_complete?
|
681
916
|
if @pending
|
682
|
-
|
683
|
-
|
917
|
+
if ready?
|
918
|
+
@pending = false
|
684
919
|
EventMachine::event_callback uuid, ConnectionCompleted, ""
|
685
920
|
end
|
686
|
-
else
|
687
|
-
super
|
688
921
|
end
|
922
|
+
@pending
|
689
923
|
end
|
690
924
|
|
925
|
+
def select_for_writing?
|
926
|
+
pending?
|
927
|
+
super
|
928
|
+
end
|
691
929
|
|
692
|
-
|
930
|
+
def select_for_reading?
|
931
|
+
pending?
|
932
|
+
super
|
933
|
+
end
|
693
934
|
end
|
694
935
|
end
|
695
936
|
|
@@ -809,7 +1050,8 @@ module EventMachine
|
|
809
1050
|
begin
|
810
1051
|
10.times {
|
811
1052
|
descriptor,peername = io.accept_nonblock
|
812
|
-
sd =
|
1053
|
+
sd = EvmaTCPClient.new descriptor
|
1054
|
+
sd.is_server = true
|
813
1055
|
EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
|
814
1056
|
}
|
815
1057
|
rescue Errno::EWOULDBLOCK, Errno::EAGAIN
|
@@ -1005,18 +1247,14 @@ module EventMachine
|
|
1005
1247
|
@close_scheduled = true
|
1006
1248
|
EventMachine::event_callback uuid, ConnectionUnbound, nil
|
1007
1249
|
end
|
1008
|
-
|
1009
1250
|
end
|
1010
1251
|
|
1011
|
-
|
1012
1252
|
def send_data data
|
1013
1253
|
send_datagram data, @return_address
|
1014
1254
|
end
|
1015
|
-
|
1016
1255
|
end
|
1017
1256
|
end
|
1018
1257
|
|
1019
1258
|
# load base EM api on top, now that we have the underlying pure ruby
|
1020
1259
|
# implementation defined
|
1021
1260
|
require 'eventmachine'
|
1022
|
-
|