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

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.
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