eventmachine 1.2.0.1 → 1.2.1

Sign up to get free protection for your applications and to get access to all the features.
@@ -521,11 +521,27 @@ public class EmReactor {
521
521
  }
522
522
 
523
523
  public Object[] getPeerName (long sig) {
524
- return Connections.get(sig).getPeerName();
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
- return Connections.get(sig).getSockName();
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) {
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
- # Example:
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
- # EM.run do
10
- # pool = EM::Pool.new
11
- # spawn = lambda { pool.add EM::HttpRequest.new('http://example.org') }
12
- # 10.times { spawn[] }
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
- # For example:
68
- # pool.contents.inject(0) { |sum, connection| connection.num_bytes }
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
- if ix = remaining_data.index( @lt2_delimiter )
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+@lt2_delimiter.length)..-1]
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.to_s
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 ) or raise "unknown close_connection 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
- false
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 get_peername target"
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 get_peername target"
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
- module EventMachine
231
- # @private
232
- class Error < Exception; end
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
- #@loopbreak_writer.write '+' if @loopbreak_writer
418
- @loopbreak_writer.send('+',0,"127.0.0.1",@loopbreak_port) if @loopbreak_writer
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
- attr_reader :io, :uuid
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
- rescue EOFError, Errno::ECONNRESET, Errno::ECONNREFUSED
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
- def select_for_writing?
673
- @pending ? true : super
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 select_for_reading?
677
- @pending ? false : super
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 eventable_write
914
+ def pending?
915
+ handshake_complete?
681
916
  if @pending
682
- @pending = false
683
- if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
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 = StreamObject.new descriptor
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
-