sonixlabs-eventmachine-java 1.0.0.rc.7-java → 1.0.3.1-java

Sign up to get free protection for your applications and to get access to all the features.
Files changed (58) hide show
  1. checksums.yaml +4 -12
  2. data/.travis.yml +12 -0
  3. data/CHANGELOG.md +33 -0
  4. data/Gemfile +0 -1
  5. data/README.md +2 -2
  6. data/README_JP.md +10 -2
  7. data/eventmachine.gemspec +10 -7
  8. data/ext/binder.cpp +1 -1
  9. data/ext/cmain.cpp +11 -0
  10. data/ext/ed.cpp +22 -7
  11. data/ext/ed.h +5 -5
  12. data/ext/em.cpp +64 -66
  13. data/ext/em.h +10 -5
  14. data/ext/eventmachine.h +1 -0
  15. data/ext/extconf.rb +4 -3
  16. data/ext/fastfilereader/extconf.rb +1 -1
  17. data/ext/rubymain.cpp +22 -1
  18. data/ext/ssl.cpp +1 -1
  19. data/java/.classpath +1 -3
  20. data/java/.gitignore +1 -0
  21. data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
  22. data/java/src/com/rubyeventmachine/EmReactor.java +502 -561
  23. data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
  24. data/java/src/com/rubyeventmachine/EventCode.java +26 -0
  25. data/java/src/com/rubyeventmachine/EventableChannel.java +102 -42
  26. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +146 -161
  27. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +371 -334
  28. data/java/src/com/rubyeventmachine/SslBox.java +310 -0
  29. data/lib/em/iterator.rb +5 -44
  30. data/lib/em/processes.rb +1 -1
  31. data/lib/em/protocols/httpclient.rb +2 -2
  32. data/lib/em/protocols/line_protocol.rb +2 -2
  33. data/lib/em/protocols/smtpclient.rb +1 -1
  34. data/lib/em/protocols/smtpserver.rb +10 -7
  35. data/lib/em/protocols/stomp.rb +5 -2
  36. data/lib/em/protocols.rb +1 -0
  37. data/lib/em/version.rb +1 -1
  38. data/lib/eventmachine.rb +35 -14
  39. data/lib/jeventmachine.rb +65 -18
  40. data/rakelib/package.rake +15 -18
  41. data/tests/server.crt +36 -0
  42. data/tests/server.key +51 -0
  43. data/tests/test_attach.rb +24 -0
  44. data/tests/test_connection_count.rb +21 -1
  45. data/tests/test_epoll.rb +15 -0
  46. data/tests/test_httpclient2.rb +5 -0
  47. data/tests/test_idle_connection.rb +6 -4
  48. data/tests/test_iterator.rb +97 -0
  49. data/tests/test_line_protocol.rb +33 -0
  50. data/tests/test_pause.rb +24 -0
  51. data/tests/test_set_sock_opt.rb +1 -1
  52. data/tests/test_ssl_echo_data.rb +60 -0
  53. data/tests/test_ssl_methods.rb +15 -7
  54. data/tests/test_ssl_verify.rb +4 -4
  55. data/tests/test_stomp.rb +37 -0
  56. data/tests/test_system.rb +42 -0
  57. metadata +45 -42
  58. data/lib/rubyeventmachine.jar +0 -0
@@ -0,0 +1,310 @@
1
+ package com.rubyeventmachine;
2
+
3
+ import java.io.IOException;
4
+ import java.nio.ByteBuffer;
5
+ import java.nio.channels.SelectionKey;
6
+ import java.nio.channels.SocketChannel;
7
+ import java.security.KeyManagementException;
8
+ import java.security.KeyStore;
9
+ import java.security.KeyStoreException;
10
+ import java.security.NoSuchAlgorithmException;
11
+ import java.security.UnrecoverableKeyException;
12
+
13
+ import javax.net.ssl.KeyManager;
14
+ import javax.net.ssl.KeyManagerFactory;
15
+ import javax.net.ssl.SSLContext;
16
+ import javax.net.ssl.SSLEngine;
17
+ import javax.net.ssl.SSLEngineResult;
18
+ import javax.net.ssl.SSLEngineResult.HandshakeStatus;
19
+ import javax.net.ssl.SSLEngineResult.Status;
20
+ import javax.net.ssl.SSLPeerUnverifiedException;
21
+ import javax.net.ssl.TrustManager;
22
+ import javax.net.ssl.X509TrustManager;
23
+
24
+ public class SslBox {
25
+
26
+ private final SSLContext sslContext;
27
+ private final SSLEngine sslEngine;
28
+
29
+ private final ByteBuffer netInBuffer;
30
+ private final ByteBuffer netOutBuffer;
31
+ private final ByteBuffer anotherBuffer;
32
+
33
+ public static ByteBuffer emptyBuf = ByteBuffer.allocate(0);
34
+ private final SocketChannel channel;
35
+
36
+ private boolean handshakeComplete;
37
+ protected HandshakeStatus handshakeStatus; //gets set by handshake
38
+
39
+ public SslBox(boolean isServer, SocketChannel channel, KeyStore keyStore, X509TrustManager tm, boolean verifyPeer, String host, int port) {
40
+ try {
41
+ sslContext = SSLContext.getInstance("TLS");
42
+ KeyManager[] keyManagers = null;
43
+
44
+ if (keyStore != null) {
45
+ KeyManagerFactory kmf = KeyManagerFactory.getInstance("SunX509");
46
+ kmf.init(keyStore, null);
47
+ keyManagers = kmf.getKeyManagers();
48
+ }
49
+
50
+ sslContext.init(keyManagers, new TrustManager[] { tm }, null);
51
+ sslEngine = sslContext.createSSLEngine(host, port);
52
+ sslEngine.setUseClientMode(!isServer);
53
+ sslEngine.setNeedClientAuth(verifyPeer);
54
+
55
+ this.channel = channel;
56
+
57
+ int netBufSize = sslEngine.getSession().getPacketBufferSize();
58
+ netInBuffer = ByteBuffer.allocate(netBufSize);
59
+ netOutBuffer = ByteBuffer.allocate(netBufSize);
60
+ anotherBuffer = ByteBuffer.allocate(netBufSize);
61
+ reset();
62
+ } catch (NoSuchAlgorithmException e) {
63
+ throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
64
+ } catch (UnrecoverableKeyException e) {
65
+ throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
66
+ } catch (KeyStoreException e) {
67
+ throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
68
+ } catch (KeyManagementException e) {
69
+ throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
70
+ } catch (IOException e) {
71
+ throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
72
+ }
73
+ }
74
+
75
+ public void reset() throws IOException {
76
+ netOutBuffer.position(0);
77
+ netOutBuffer.limit(0);
78
+ netInBuffer.position(0);
79
+ netInBuffer.limit(0);
80
+ handshakeComplete = false;
81
+ //initiate handshake
82
+ sslEngine.beginHandshake();
83
+ handshakeStatus = sslEngine.getHandshakeStatus();
84
+ }
85
+
86
+ public boolean handshake(SelectionKey channelKey) {
87
+ try {
88
+ int newOps = do_handshake(channelKey.isReadable(), channelKey.isWritable());
89
+ channelKey.interestOps(newOps);
90
+ } catch (IOException e) {
91
+ return false;
92
+ }
93
+ return true;
94
+ }
95
+
96
+ public boolean handshakeNeeded() {
97
+ return !handshakeComplete;
98
+ }
99
+
100
+ private int do_handshake(boolean read, boolean write) throws IOException {
101
+ if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still have data to write
102
+
103
+ SSLEngineResult handshake = null;
104
+
105
+ while (!handshakeComplete) {
106
+ switch ( handshakeStatus ) {
107
+ case FINISHED: {
108
+ //we are complete if we have delivered the last package
109
+ handshakeComplete = !netOutBuffer.hasRemaining();
110
+ //return 0 if we are complete, otherwise we still have data to write
111
+ return handshakeComplete?0:SelectionKey.OP_WRITE;
112
+ }
113
+ case NEED_WRAP: {
114
+ //perform the wrap function
115
+ handshake = handshakeWrap(write);
116
+ if ( handshake.getStatus() == Status.OK ){
117
+ if (handshakeStatus == HandshakeStatus.NEED_TASK)
118
+ handshakeStatus = tasks();
119
+ } else {
120
+ //wrap should always work with our buffers
121
+ throw new IOException("Unexpected status:" + handshake.getStatus() + " during handshake WRAP.");
122
+ }
123
+ if ( handshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) {
124
+ //should actually return OP_READ if we have NEED_UNWRAP
125
+ return SelectionKey.OP_WRITE;
126
+ }
127
+ //fall down to NEED_UNWRAP on the same call, will result in a
128
+ //BUFFER_UNDERFLOW if it needs data
129
+ }
130
+ //$FALL-THROUGH$
131
+ case NEED_UNWRAP: {
132
+ //perform the unwrap function
133
+ handshake = handshakeUnwrap(read);
134
+ if ( handshake.getStatus() == Status.OK ) {
135
+ if (handshakeStatus == HandshakeStatus.NEED_TASK)
136
+ handshakeStatus = tasks();
137
+ } else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){
138
+ //read more data, reregister for OP_READ
139
+ return SelectionKey.OP_READ;
140
+ } else {
141
+ throw new IOException("Invalid handshake status:"+handshakeStatus+" during handshake UNWRAP.");
142
+ }//switch
143
+ break;
144
+ }
145
+ case NEED_TASK: {
146
+ handshakeStatus = tasks();
147
+ break;
148
+ }
149
+ default: throw new IllegalStateException("Invalid handshake status:"+handshakeStatus);
150
+ }//switch
151
+ }//while
152
+ //return 0 if we are complete, otherwise reregister for any activity that
153
+ //would cause this method to be called again.
154
+ return handshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
155
+ }
156
+
157
+
158
+ /**
159
+ * Performs the WRAP function
160
+ * @param doWrite boolean
161
+ * @return SSLEngineResult
162
+ * @throws IOException
163
+ */
164
+ private SSLEngineResult handshakeWrap(boolean doWrite) throws IOException {
165
+ //this should never be called with a network buffer that contains data
166
+ //so we can clear it here.
167
+ netOutBuffer.clear();
168
+ //perform the wrap
169
+ SSLEngineResult result = sslEngine.wrap(emptyBuf, netOutBuffer);
170
+ //prepare the results to be written
171
+ netOutBuffer.flip();
172
+ //set the status
173
+ handshakeStatus = result.getHandshakeStatus();
174
+ //optimization, if we do have a writable channel, write it now
175
+ if ( doWrite ) flush(netOutBuffer);
176
+ return result;
177
+ }
178
+
179
+ /**
180
+ * Perform handshake unwrap
181
+ * @param doread boolean
182
+ * @return SSLEngineResult
183
+ * @throws IOException
184
+ */
185
+ private SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
186
+
187
+ if (netInBuffer.position() == netInBuffer.limit()) {
188
+ //clear the buffer if we have emptied it out on data
189
+ netInBuffer.clear();
190
+ }
191
+ if ( doread ) {
192
+ //if we have data to read, read it
193
+ int read = channel.read(netInBuffer);
194
+ if (read == -1) throw new IOException("EOF encountered during handshake.");
195
+ }
196
+ SSLEngineResult result;
197
+ boolean cont = false;
198
+ //loop while we can perform pure SSLEngine data
199
+ do {
200
+ //prepare the buffer with the incoming data
201
+ netInBuffer.flip();
202
+ //call unwrap
203
+ result = sslEngine.unwrap(netInBuffer, anotherBuffer);
204
+ //compact the buffer, this is an optional method, wonder what would happen if we didn't
205
+ netInBuffer.compact();
206
+ //read in the status
207
+ handshakeStatus = result.getHandshakeStatus();
208
+ if ( result.getStatus() == SSLEngineResult.Status.OK &&
209
+ result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
210
+ //execute tasks if we need to
211
+ handshakeStatus = tasks();
212
+ }
213
+ //perform another unwrap?
214
+ cont = result.getStatus() == SSLEngineResult.Status.OK &&
215
+ handshakeStatus == HandshakeStatus.NEED_UNWRAP;
216
+ }while ( cont );
217
+ return result;
218
+ }
219
+
220
+ /**
221
+ * Executes all the tasks needed on the same thread.
222
+ * @return HandshakeStatus
223
+ */
224
+ private SSLEngineResult.HandshakeStatus tasks() {
225
+ Runnable r = null;
226
+ while ( (r = sslEngine.getDelegatedTask()) != null) {
227
+ r.run();
228
+ }
229
+ return sslEngine.getHandshakeStatus();
230
+ }
231
+
232
+ protected boolean flush(ByteBuffer buf) throws IOException {
233
+ int remaining = buf.remaining();
234
+ if ( remaining > 0 ) {
235
+ int written = channel.write(buf);
236
+ return written >= remaining;
237
+ }else {
238
+ return true;
239
+ }
240
+ }
241
+
242
+ public javax.security.cert.X509Certificate getPeerCert() throws SSLPeerUnverifiedException {
243
+ return sslEngine.getSession().getPeerCertificateChain()[0];
244
+ }
245
+
246
+ public int write(ByteBuffer src) throws IOException {
247
+ if (!flush(netOutBuffer)) return 0;
248
+
249
+ netOutBuffer.clear();
250
+
251
+ SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
252
+ int written = result.bytesConsumed();
253
+ netOutBuffer.flip();
254
+
255
+ if (result.getStatus() == Status.OK) {
256
+ if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
257
+ tasks();
258
+ } else {
259
+ throw new IOException("Unable to wrap data, invalid engine state: " +result.getStatus());
260
+ }
261
+
262
+ //force a flush
263
+ flush(netOutBuffer);
264
+
265
+ return written;
266
+ }
267
+
268
+ public int read(ByteBuffer dst) throws IOException {
269
+ //did we finish our handshake?
270
+ if (!handshakeComplete) throw new IllegalStateException("Handshake incomplete, you must complete handshake before reading data.");
271
+
272
+ //read from the network
273
+ int netread = channel.read(netInBuffer);
274
+ //did we reach EOF? if so send EOF up one layer.
275
+ if (netread == -1) return -1;
276
+
277
+ //the data read
278
+ int read = 0;
279
+ //the SSL engine result
280
+ SSLEngineResult unwrap;
281
+ do {
282
+ //prepare the buffer
283
+ netInBuffer.flip();
284
+ //unwrap the data
285
+ unwrap = sslEngine.unwrap(netInBuffer, dst);
286
+ //compact the buffer
287
+ netInBuffer.compact();
288
+
289
+ if ( unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW ) {
290
+ //we did receive some data, add it to our total
291
+ read += unwrap.bytesProduced();
292
+ //perform any tasks if needed
293
+ if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
294
+ //if we need more network data, then bail out for now.
295
+ if ( unwrap.getStatus() == Status.BUFFER_UNDERFLOW ) break;
296
+ }else if ( unwrap.getStatus()==Status.BUFFER_OVERFLOW && read>0 ) {
297
+ //buffer overflow can happen, if we have read data, then
298
+ //empty out the dst buffer before we do another read
299
+ break;
300
+ }else {
301
+ //here we should trap BUFFER_OVERFLOW and call expand on the buffer
302
+ //for now, throw an exception, as we initialized the buffers
303
+ //in the constructor
304
+ throw new IOException("Unable to unwrap data, invalid status: " + unwrap.getStatus());
305
+ }
306
+ } while ( (netInBuffer.position() != 0)); //continue to unwrapping as long as the input buffer has stuff
307
+ return (read);
308
+ }
309
+
310
+ }
data/lib/em/iterator.rb CHANGED
@@ -50,6 +50,7 @@ module EventMachine
50
50
  #
51
51
  def initialize(list, concurrency = 1)
52
52
  raise ArgumentError, 'argument must be an array' unless list.respond_to?(:to_a)
53
+ raise ArgumentError, 'concurrency must be bigger than zero' unless (concurrency > 0)
53
54
  @list = list.to_a.dup
54
55
  @concurrency = concurrency
55
56
 
@@ -224,47 +225,7 @@ module EventMachine
224
225
  end
225
226
  end
226
227
 
227
- if __FILE__ == $0
228
- $:.unshift File.join(File.dirname(__FILE__), '..')
229
- require 'eventmachine'
230
-
231
- # TODO: real tests
232
- # TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
233
- # TODO: support iter.pause/resume/stop/break/continue?
234
- # TODO: create some exceptions instead of using RuntimeError
235
- # TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
236
-
237
- EM.run{
238
- EM::Iterator.new(1..50).each{ |num,iter| p num; iter.next }
239
- EM::Iterator.new([1,2,3], 10).each{ |num,iter| p num; iter.next }
240
-
241
- i = EM::Iterator.new(1..100, 5)
242
- i.each(proc{|num,iter|
243
- p num.to_s
244
- iter.next
245
- }, proc{
246
- p :done
247
- })
248
- EM.add_timer(0.03){
249
- i.concurrency = 1
250
- }
251
- EM.add_timer(0.04){
252
- i.concurrency = 3
253
- }
254
-
255
- EM::Iterator.new(100..150).map(proc{ |num,iter|
256
- EM.add_timer(0.01){ iter.return(num) }
257
- }, proc{ |results|
258
- p results
259
- })
260
-
261
- EM::Iterator.new(%w[ pwd uptime uname date ], 2).inject({}, proc{ |hash,cmd,iter|
262
- EM.system(cmd){ |output,status|
263
- hash[cmd] = status.exitstatus == 0 ? output.strip : nil
264
- iter.return(hash)
265
- }
266
- }, proc{ |results|
267
- p results
268
- })
269
- }
270
- end
228
+ # TODO: pass in one object instead of two? .each{ |iter| puts iter.current; iter.next }
229
+ # TODO: support iter.pause/resume/stop/break/continue?
230
+ # TODO: create some exceptions instead of using RuntimeError
231
+ # TODO: support proc instead of enumerable? EM::Iterator.new(proc{ return queue.pop })
data/lib/em/processes.rb CHANGED
@@ -114,7 +114,7 @@ module EventMachine
114
114
  init = args.pop if args.last.is_a? Proc
115
115
 
116
116
  # merge remaining arguments into the command
117
- cmd = ([cmd] + args.map{|a|a.to_s.dump}).join(' ')
117
+ cmd = [cmd, *args] if args.any?
118
118
 
119
119
  EM.get_subprocess_pid(EM.popen(cmd, SystemCmd, cb) do |c|
120
120
  init[c] if init
@@ -127,7 +127,7 @@ module EventMachine
127
127
  # Allow an override for the host header if it's not the connect-string.
128
128
  host = args[:host_header] || args[:host] || "_"
129
129
  # For now, ALWAYS tuck in the port string, although we may want to omit it if it's the default.
130
- port = args[:port]
130
+ port = args[:port].to_i != 80 ? ":#{args[:port]}" : ""
131
131
 
132
132
  # POST items.
133
133
  postcontenttype = args[:contenttype] || "application/octet-stream"
@@ -138,7 +138,7 @@ module EventMachine
138
138
  # TODO: We ASSUME the caller wants to send a 1.1 request. May not be a good assumption.
139
139
  req = [
140
140
  "#{verb} #{request}#{qs} HTTP/#{version}",
141
- "Host: #{host}:#{port}",
141
+ "Host: #{host}#{port}",
142
142
  "User-agent: Ruby EventMachine",
143
143
  ]
144
144
 
@@ -15,8 +15,8 @@ module EventMachine
15
15
  def receive_data data
16
16
  (@buf ||= '') << data
17
17
 
18
- while line = @buf.slice!(/(.*)\r?\n/)
19
- receive_line(line)
18
+ while @buf.slice!(/(.*?)\r?\n/)
19
+ receive_line($1)
20
20
  end
21
21
  end
22
22
 
@@ -271,7 +271,7 @@ module EventMachine
271
271
  psw = psw.call
272
272
  end
273
273
  #str = Base64::encode64("\0#{@args[:auth][:username]}\0#{psw}").chomp
274
- str = ["\0#{@args[:auth][:username]}\0#{psw}"].pack("m").chomp
274
+ str = ["\0#{@args[:auth][:username]}\0#{psw}"].pack("m").gsub(/\n/, '')
275
275
  send_data "AUTH PLAIN #{str}\r\n"
276
276
  @responder = :receive_auth_response
277
277
  else
@@ -506,11 +506,13 @@ module EventMachine
506
506
  # Since we clear the chunk array every time we submit it, the caller needs to be
507
507
  # aware to do things like dup it if he wants to keep it around across calls.
508
508
  #
509
- # DON'T reset the transaction upon disposition of the incoming message.
510
- # This means another DATA command can be accepted with the same sender and recipients.
511
- # If the client wants to reset, he can call RSET.
512
- # Not sure whether the standard requires a transaction-reset at this point, but it
513
- # appears not to.
509
+ # Resets the transaction upon disposition of the incoming message.
510
+ # RFC5321 says this about the MAIL FROM command:
511
+ # "This command tells the SMTP-receiver that a new mail transaction is
512
+ # starting and to reset all its state tables and buffers, including any
513
+ # recipients or mail data."
514
+ #
515
+ # Equivalent behaviour is implemented by resetting after a completed transaction.
514
516
  #
515
517
  # User-written code can return a Deferrable as a response from receive_message.
516
518
  #
@@ -524,11 +526,12 @@ module EventMachine
524
526
 
525
527
  succeeded = proc {
526
528
  send_data "250 Message accepted\r\n"
529
+ reset_protocol_state
527
530
  }
528
531
  failed = proc {
529
532
  send_data "550 Message rejected\r\n"
533
+ reset_protocol_state
530
534
  }
531
-
532
535
  d = receive_message
533
536
 
534
537
  if d.respond_to?(:set_deferred_status)
@@ -541,7 +544,7 @@ module EventMachine
541
544
  @state.delete :data
542
545
  else
543
546
  # slice off leading . if any
544
- ln.slice!(0...1) if ln[0] == 46
547
+ ln.slice!(0...1) if ln[0] == ?.
545
548
  @databuffer << ln
546
549
  if @databuffer.length > @@parms[:chunksize]
547
550
  receive_data_chunk @databuffer
@@ -104,12 +104,15 @@ module EventMachine
104
104
 
105
105
  # @private
106
106
  def send_frame verb, headers={}, body=""
107
+ body = body.to_s
107
108
  ary = [verb, "\n"]
109
+ body_bytesize = body.bytesize if body.respond_to? :bytesize
110
+ body_bytesize ||= body.size
108
111
  headers.each {|k,v| ary << "#{k}:#{v}\n" }
109
- ary << "content-length: #{body.to_s.length}\n"
112
+ ary << "content-length: #{body_bytesize}\n"
110
113
  ary << "content-type: text/plain; charset=UTF-8\n" unless headers.has_key? 'content-type'
111
114
  ary << "\n"
112
- ary << body.to_s
115
+ ary << body
113
116
  ary << "\0"
114
117
  send_data ary.join
115
118
  end
data/lib/em/protocols.rb CHANGED
@@ -32,5 +32,6 @@ module EventMachine
32
32
  autoload :Postgres3, 'em/protocols/postgres3'
33
33
  autoload :ObjectProtocol, 'em/protocols/object_protocol'
34
34
  autoload :Socks4, 'em/protocols/socks4'
35
+ autoload :LineProtocol, 'em/protocols/line_protocol'
35
36
  end
36
37
  end
data/lib/em/version.rb CHANGED
@@ -1,3 +1,3 @@
1
1
  module EventMachine
2
- VERSION = "1.0.0.rc.7"
2
+ VERSION = "1.0.3.1"
3
3
  end
data/lib/eventmachine.rb CHANGED
@@ -1,8 +1,8 @@
1
- if RUBY_PLATFORM =~ /java/
1
+ if defined?(EventMachine.library_type) and EventMachine.library_type == :pure_ruby
2
+ # assume 'em/pure_ruby' was loaded already
3
+ elsif RUBY_PLATFORM =~ /java/
2
4
  require 'java'
3
5
  require 'jeventmachine'
4
- elsif defined?(EventMachine.library_type) and EventMachine.library_type == :pure_ruby
5
- # assume 'em/pure_ruby' was loaded already
6
6
  else
7
7
  begin
8
8
  require 'rubyeventmachine'
@@ -156,7 +156,7 @@ module EventMachine
156
156
  # will start without release_machine being called and will immediately throw
157
157
 
158
158
  #
159
- if reactor_running? and @reactor_pid != Process.pid
159
+ if @reactor_running and @reactor_pid != Process.pid
160
160
  # Reactor was started in a different parent, meaning we have forked.
161
161
  # Clean up reactor state so a new reactor boots up in this child.
162
162
  stop_event_loop
@@ -531,6 +531,15 @@ module EventMachine
531
531
  s
532
532
  end
533
533
 
534
+ # Attach to an existing socket's file descriptor. The socket may have been
535
+ # started with {EventMachine.start_server}.
536
+ def self.attach_server sock, handler=nil, *args, &block
537
+ klass = klass_from_handler(Connection, handler, *args)
538
+ sd = sock.respond_to?(:fileno) ? sock.fileno : sock
539
+ s = attach_sd(sd)
540
+ @acceptors[s] = [klass,args,block,sock]
541
+ s
542
+ end
534
543
 
535
544
  # Stop a TCP server socket that was started with {EventMachine.start_server}.
536
545
  # @see EventMachine.start_server
@@ -1156,7 +1165,12 @@ module EventMachine
1156
1165
  # Perhaps misnamed since the underlying function uses socketpair and is full-duplex.
1157
1166
 
1158
1167
  klass = klass_from_handler(Connection, handler, *args)
1159
- w = Shellwords::shellwords( cmd )
1168
+ w = case cmd
1169
+ when Array
1170
+ cmd
1171
+ when String
1172
+ Shellwords::shellwords( cmd )
1173
+ end
1160
1174
  w.unshift( w.first ) if w.first
1161
1175
  s = invoke_popen( w )
1162
1176
  c = klass.new s, *args
@@ -1176,7 +1190,7 @@ module EventMachine
1176
1190
  #
1177
1191
  # @return [Boolean] true if the EventMachine reactor loop is currently running
1178
1192
  def self.reactor_running?
1179
- (@reactor_running || false)
1193
+ @reactor_running && Process.pid == @reactor_pid
1180
1194
  end
1181
1195
 
1182
1196
 
@@ -1426,7 +1440,8 @@ module EventMachine
1426
1440
  # runs down open connections). It should go on the other calls to user
1427
1441
  # code, but the performance impact may be too large.
1428
1442
  #
1429
- if opcode == ConnectionUnbound
1443
+ case opcode
1444
+ when ConnectionUnbound
1430
1445
  if c = @conns.delete( conn_binding )
1431
1446
  begin
1432
1447
  if c.original_method(:unbind).arity != 0
@@ -1456,7 +1471,7 @@ module EventMachine
1456
1471
  raise ConnectionNotBound, "received ConnectionUnbound for an unknown signature: #{conn_binding}"
1457
1472
  end
1458
1473
  end
1459
- elsif opcode == ConnectionAccepted
1474
+ when ConnectionAccepted
1460
1475
  accep,args,blk = @acceptors[conn_binding]
1461
1476
  raise NoHandlerForAcceptedConnection unless accep
1462
1477
  c = accep.new data, *args
@@ -1466,25 +1481,31 @@ module EventMachine
1466
1481
  ##
1467
1482
  # The remaining code is a fallback for the pure ruby and java reactors.
1468
1483
  # In the C++ reactor, these events are handled in the C event_callback() in rubymain.cpp
1469
- elsif opcode == ConnectionCompleted
1484
+ when ConnectionCompleted
1470
1485
  c = @conns[conn_binding] or raise ConnectionNotBound, "received ConnectionCompleted for unknown signature: #{conn_binding}"
1471
1486
  c.connection_completed
1472
- elsif opcode == TimerFired
1487
+ when TimerFired
1473
1488
  t = @timers.delete( data )
1474
1489
  return if t == false # timer cancelled
1475
1490
  t or raise UnknownTimerFired, "timer data: #{data}"
1476
1491
  t.call
1477
- elsif opcode == ConnectionData
1492
+ when ConnectionData
1478
1493
  c = @conns[conn_binding] or raise ConnectionNotBound, "received data #{data} for unknown signature: #{conn_binding}"
1479
1494
  c.receive_data data
1480
- elsif opcode == LoopbreakSignalled
1495
+ when LoopbreakSignalled
1481
1496
  run_deferred_callbacks
1482
- elsif opcode == ConnectionNotifyReadable
1497
+ when ConnectionNotifyReadable
1483
1498
  c = @conns[conn_binding] or raise ConnectionNotBound
1484
1499
  c.notify_readable
1485
- elsif opcode == ConnectionNotifyWritable
1500
+ when ConnectionNotifyWritable
1486
1501
  c = @conns[conn_binding] or raise ConnectionNotBound
1487
1502
  c.notify_writable
1503
+ when SslHandshakeCompleted
1504
+ c = @conns[conn_binding] or raise ConnectionNotBound
1505
+ c.ssl_handshake_completed
1506
+ when SslVerify
1507
+ c = @conns[conn_binding] or raise ConnectionNotBound
1508
+ EventMachine::ssl_verify_peer c, data
1488
1509
  end
1489
1510
  end
1490
1511