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.
- checksums.yaml +4 -12
- data/.travis.yml +12 -0
- data/CHANGELOG.md +33 -0
- data/Gemfile +0 -1
- data/README.md +2 -2
- data/README_JP.md +10 -2
- data/eventmachine.gemspec +10 -7
- data/ext/binder.cpp +1 -1
- data/ext/cmain.cpp +11 -0
- data/ext/ed.cpp +22 -7
- data/ext/ed.h +5 -5
- data/ext/em.cpp +64 -66
- data/ext/em.h +10 -5
- data/ext/eventmachine.h +1 -0
- data/ext/extconf.rb +4 -3
- data/ext/fastfilereader/extconf.rb +1 -1
- data/ext/rubymain.cpp +22 -1
- data/ext/ssl.cpp +1 -1
- data/java/.classpath +1 -3
- data/java/.gitignore +1 -0
- data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
- data/java/src/com/rubyeventmachine/EmReactor.java +502 -561
- data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
- data/java/src/com/rubyeventmachine/EventCode.java +26 -0
- data/java/src/com/rubyeventmachine/EventableChannel.java +102 -42
- data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +146 -161
- data/java/src/com/rubyeventmachine/EventableSocketChannel.java +371 -334
- data/java/src/com/rubyeventmachine/SslBox.java +310 -0
- data/lib/em/iterator.rb +5 -44
- data/lib/em/processes.rb +1 -1
- data/lib/em/protocols/httpclient.rb +2 -2
- data/lib/em/protocols/line_protocol.rb +2 -2
- data/lib/em/protocols/smtpclient.rb +1 -1
- data/lib/em/protocols/smtpserver.rb +10 -7
- data/lib/em/protocols/stomp.rb +5 -2
- data/lib/em/protocols.rb +1 -0
- data/lib/em/version.rb +1 -1
- data/lib/eventmachine.rb +35 -14
- data/lib/jeventmachine.rb +65 -18
- data/rakelib/package.rake +15 -18
- data/tests/server.crt +36 -0
- data/tests/server.key +51 -0
- data/tests/test_attach.rb +24 -0
- data/tests/test_connection_count.rb +21 -1
- data/tests/test_epoll.rb +15 -0
- data/tests/test_httpclient2.rb +5 -0
- data/tests/test_idle_connection.rb +6 -4
- data/tests/test_iterator.rb +97 -0
- data/tests/test_line_protocol.rb +33 -0
- data/tests/test_pause.rb +24 -0
- data/tests/test_set_sock_opt.rb +1 -1
- data/tests/test_ssl_echo_data.rb +60 -0
- data/tests/test_ssl_methods.rb +15 -7
- data/tests/test_ssl_verify.rb +4 -4
- data/tests/test_stomp.rb +37 -0
- data/tests/test_system.rb +42 -0
- metadata +45 -42
- 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
|
-
|
228
|
-
|
229
|
-
|
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 =
|
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}
|
141
|
+
"Host: #{host}#{port}",
|
142
142
|
"User-agent: Ruby EventMachine",
|
143
143
|
]
|
144
144
|
|
@@ -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").
|
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
|
-
#
|
510
|
-
#
|
511
|
-
#
|
512
|
-
#
|
513
|
-
#
|
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] ==
|
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
|
data/lib/em/protocols/stomp.rb
CHANGED
@@ -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: #{
|
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
|
115
|
+
ary << body
|
113
116
|
ary << "\0"
|
114
117
|
send_data ary.join
|
115
118
|
end
|
data/lib/em/protocols.rb
CHANGED
data/lib/em/version.rb
CHANGED
data/lib/eventmachine.rb
CHANGED
@@ -1,8 +1,8 @@
|
|
1
|
-
if
|
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
|
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 =
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
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
|
-
|
1495
|
+
when LoopbreakSignalled
|
1481
1496
|
run_deferred_callbacks
|
1482
|
-
|
1497
|
+
when ConnectionNotifyReadable
|
1483
1498
|
c = @conns[conn_binding] or raise ConnectionNotBound
|
1484
1499
|
c.notify_readable
|
1485
|
-
|
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
|
|