sensu-em 2.4.0-x86-mingw32
This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
- checksums.yaml +7 -0
- data/.gitignore +21 -0
- data/.travis.yml +12 -0
- data/.yardopts +7 -0
- data/CHANGELOG.md +33 -0
- data/GNU +281 -0
- data/Gemfile +2 -0
- data/LICENSE +60 -0
- data/README.md +109 -0
- data/Rakefile +20 -0
- data/docs/DocumentationGuidesIndex.md +27 -0
- data/docs/GettingStarted.md +521 -0
- data/docs/old/ChangeLog +211 -0
- data/docs/old/DEFERRABLES +246 -0
- data/docs/old/EPOLL +141 -0
- data/docs/old/INSTALL +13 -0
- data/docs/old/KEYBOARD +42 -0
- data/docs/old/LEGAL +25 -0
- data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
- data/docs/old/PURE_RUBY +75 -0
- data/docs/old/RELEASE_NOTES +94 -0
- data/docs/old/SMTP +4 -0
- data/docs/old/SPAWNED_PROCESSES +148 -0
- data/docs/old/TODO +8 -0
- data/eventmachine.gemspec +37 -0
- data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
- data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
- data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
- data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
- data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
- data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
- data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
- data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
- data/examples/old/ex_channel.rb +43 -0
- data/examples/old/ex_queue.rb +2 -0
- data/examples/old/ex_tick_loop_array.rb +15 -0
- data/examples/old/ex_tick_loop_counter.rb +32 -0
- data/examples/old/helper.rb +2 -0
- data/ext/binder.cpp +124 -0
- data/ext/binder.h +46 -0
- data/ext/cmain.cpp +887 -0
- data/ext/ed.cpp +1992 -0
- data/ext/ed.h +424 -0
- data/ext/em.cpp +2352 -0
- data/ext/em.h +253 -0
- data/ext/eventmachine.h +128 -0
- data/ext/extconf.rb +179 -0
- data/ext/fastfilereader/extconf.rb +103 -0
- data/ext/fastfilereader/mapper.cpp +214 -0
- data/ext/fastfilereader/mapper.h +59 -0
- data/ext/fastfilereader/rubymain.cpp +127 -0
- data/ext/kb.cpp +79 -0
- data/ext/page.cpp +107 -0
- data/ext/page.h +51 -0
- data/ext/pipe.cpp +347 -0
- data/ext/project.h +161 -0
- data/ext/rubymain.cpp +1318 -0
- data/ext/ssl.cpp +476 -0
- data/ext/ssl.h +95 -0
- data/java/.classpath +6 -0
- data/java/.gitignore +1 -0
- data/java/.project +17 -0
- data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
- data/java/src/com/rubyeventmachine/EmReactor.java +531 -0
- data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
- 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 +130 -0
- data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +179 -0
- data/java/src/com/rubyeventmachine/EventableSocketChannel.java +405 -0
- data/java/src/com/rubyeventmachine/SslBox.java +311 -0
- data/lib/em/buftok.rb +110 -0
- data/lib/em/callback.rb +58 -0
- data/lib/em/channel.rb +64 -0
- data/lib/em/completion.rb +304 -0
- data/lib/em/connection.rb +716 -0
- data/lib/em/deferrable.rb +210 -0
- data/lib/em/deferrable/pool.rb +2 -0
- data/lib/em/file_watch.rb +73 -0
- data/lib/em/future.rb +61 -0
- data/lib/em/iterator.rb +231 -0
- data/lib/em/messages.rb +66 -0
- data/lib/em/pool.rb +151 -0
- data/lib/em/process_watch.rb +45 -0
- data/lib/em/processes.rb +123 -0
- data/lib/em/protocols.rb +37 -0
- data/lib/em/protocols/header_and_content.rb +138 -0
- data/lib/em/protocols/httpclient.rb +279 -0
- data/lib/em/protocols/httpclient2.rb +600 -0
- data/lib/em/protocols/line_and_text.rb +125 -0
- data/lib/em/protocols/line_protocol.rb +29 -0
- data/lib/em/protocols/linetext2.rb +161 -0
- data/lib/em/protocols/memcache.rb +331 -0
- data/lib/em/protocols/object_protocol.rb +46 -0
- data/lib/em/protocols/postgres3.rb +246 -0
- data/lib/em/protocols/saslauth.rb +175 -0
- data/lib/em/protocols/smtpclient.rb +365 -0
- data/lib/em/protocols/smtpserver.rb +643 -0
- data/lib/em/protocols/socks4.rb +66 -0
- data/lib/em/protocols/stomp.rb +205 -0
- data/lib/em/protocols/tcptest.rb +54 -0
- data/lib/em/pure_ruby.rb +1017 -0
- data/lib/em/queue.rb +71 -0
- data/lib/em/resolver.rb +209 -0
- data/lib/em/spawnable.rb +84 -0
- data/lib/em/streamer.rb +118 -0
- data/lib/em/threaded_resource.rb +90 -0
- data/lib/em/tick_loop.rb +85 -0
- data/lib/em/timers.rb +61 -0
- data/lib/em/version.rb +3 -0
- data/lib/eventmachine.rb +1553 -0
- data/lib/fastfilereaderext.rb +2 -0
- data/lib/jeventmachine.rb +321 -0
- data/lib/rubyeventmachine.rb +2 -0
- data/rakelib/cpp.rake_example +77 -0
- data/rakelib/package.rake +98 -0
- data/rakelib/test.rake +8 -0
- data/tests/client.crt +31 -0
- data/tests/client.key +51 -0
- data/tests/em_test_helper.rb +64 -0
- data/tests/server.crt +36 -0
- data/tests/server.key +51 -0
- data/tests/test_attach.rb +150 -0
- data/tests/test_basic.rb +294 -0
- data/tests/test_channel.rb +62 -0
- data/tests/test_completion.rb +177 -0
- data/tests/test_connection_count.rb +53 -0
- data/tests/test_defer.rb +18 -0
- data/tests/test_deferrable.rb +35 -0
- data/tests/test_epoll.rb +145 -0
- data/tests/test_error_handler.rb +38 -0
- data/tests/test_exc.rb +28 -0
- data/tests/test_file_watch.rb +65 -0
- data/tests/test_futures.rb +170 -0
- data/tests/test_get_sock_opt.rb +37 -0
- data/tests/test_handler_check.rb +35 -0
- data/tests/test_hc.rb +155 -0
- data/tests/test_httpclient.rb +190 -0
- data/tests/test_httpclient2.rb +133 -0
- data/tests/test_idle_connection.rb +25 -0
- data/tests/test_inactivity_timeout.rb +54 -0
- data/tests/test_iterator.rb +97 -0
- data/tests/test_kb.rb +34 -0
- data/tests/test_line_protocol.rb +33 -0
- data/tests/test_ltp.rb +138 -0
- data/tests/test_ltp2.rb +288 -0
- data/tests/test_next_tick.rb +104 -0
- data/tests/test_object_protocol.rb +36 -0
- data/tests/test_pause.rb +102 -0
- data/tests/test_pending_connect_timeout.rb +52 -0
- data/tests/test_pool.rb +194 -0
- data/tests/test_process_watch.rb +48 -0
- data/tests/test_processes.rb +128 -0
- data/tests/test_proxy_connection.rb +180 -0
- data/tests/test_pure.rb +88 -0
- data/tests/test_queue.rb +50 -0
- data/tests/test_resolver.rb +55 -0
- data/tests/test_running.rb +14 -0
- data/tests/test_sasl.rb +47 -0
- data/tests/test_send_file.rb +217 -0
- data/tests/test_servers.rb +33 -0
- data/tests/test_set_sock_opt.rb +37 -0
- data/tests/test_shutdown_hooks.rb +23 -0
- data/tests/test_smtpclient.rb +55 -0
- data/tests/test_smtpserver.rb +57 -0
- data/tests/test_spawn.rb +293 -0
- data/tests/test_ssl_args.rb +78 -0
- data/tests/test_ssl_echo_data.rb +60 -0
- data/tests/test_ssl_methods.rb +56 -0
- data/tests/test_ssl_verify.rb +82 -0
- data/tests/test_stomp.rb +37 -0
- data/tests/test_system.rb +42 -0
- data/tests/test_threaded_resource.rb +53 -0
- data/tests/test_tick_loop.rb +59 -0
- data/tests/test_timers.rb +123 -0
- data/tests/test_ud.rb +8 -0
- data/tests/test_unbind_reason.rb +48 -0
- metadata +300 -0
@@ -0,0 +1,311 @@
|
|
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.setEnabledCipherSuites(sslEngine.getSupportedCipherSuites());
|
53
|
+
sslEngine.setUseClientMode(!isServer);
|
54
|
+
sslEngine.setNeedClientAuth(verifyPeer);
|
55
|
+
|
56
|
+
this.channel = channel;
|
57
|
+
|
58
|
+
int netBufSize = sslEngine.getSession().getPacketBufferSize();
|
59
|
+
netInBuffer = ByteBuffer.allocate(netBufSize);
|
60
|
+
netOutBuffer = ByteBuffer.allocate(netBufSize);
|
61
|
+
anotherBuffer = ByteBuffer.allocate(netBufSize);
|
62
|
+
reset();
|
63
|
+
} catch (NoSuchAlgorithmException e) {
|
64
|
+
throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
|
65
|
+
} catch (UnrecoverableKeyException e) {
|
66
|
+
throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
|
67
|
+
} catch (KeyStoreException e) {
|
68
|
+
throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
|
69
|
+
} catch (KeyManagementException e) {
|
70
|
+
throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
|
71
|
+
} catch (IOException e) {
|
72
|
+
throw new RuntimeException("unable to start TLS: " + e.getMessage(), e);
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
public void reset() throws IOException {
|
77
|
+
netOutBuffer.position(0);
|
78
|
+
netOutBuffer.limit(0);
|
79
|
+
netInBuffer.position(0);
|
80
|
+
netInBuffer.limit(0);
|
81
|
+
handshakeComplete = false;
|
82
|
+
//initiate handshake
|
83
|
+
sslEngine.beginHandshake();
|
84
|
+
handshakeStatus = sslEngine.getHandshakeStatus();
|
85
|
+
}
|
86
|
+
|
87
|
+
public boolean handshake(SelectionKey channelKey) {
|
88
|
+
try {
|
89
|
+
int newOps = do_handshake(channelKey.isReadable(), channelKey.isWritable());
|
90
|
+
channelKey.interestOps(newOps);
|
91
|
+
} catch (IOException e) {
|
92
|
+
return false;
|
93
|
+
}
|
94
|
+
return true;
|
95
|
+
}
|
96
|
+
|
97
|
+
public boolean handshakeNeeded() {
|
98
|
+
return !handshakeComplete;
|
99
|
+
}
|
100
|
+
|
101
|
+
private int do_handshake(boolean read, boolean write) throws IOException {
|
102
|
+
if (!flush(netOutBuffer)) return SelectionKey.OP_WRITE; //we still have data to write
|
103
|
+
|
104
|
+
SSLEngineResult handshake = null;
|
105
|
+
|
106
|
+
while (!handshakeComplete) {
|
107
|
+
switch ( handshakeStatus ) {
|
108
|
+
case FINISHED: {
|
109
|
+
//we are complete if we have delivered the last package
|
110
|
+
handshakeComplete = !netOutBuffer.hasRemaining();
|
111
|
+
//return 0 if we are complete, otherwise we still have data to write
|
112
|
+
return handshakeComplete?0:SelectionKey.OP_WRITE;
|
113
|
+
}
|
114
|
+
case NEED_WRAP: {
|
115
|
+
//perform the wrap function
|
116
|
+
handshake = handshakeWrap(write);
|
117
|
+
if ( handshake.getStatus() == Status.OK ){
|
118
|
+
if (handshakeStatus == HandshakeStatus.NEED_TASK)
|
119
|
+
handshakeStatus = tasks();
|
120
|
+
} else {
|
121
|
+
//wrap should always work with our buffers
|
122
|
+
throw new IOException("Unexpected status:" + handshake.getStatus() + " during handshake WRAP.");
|
123
|
+
}
|
124
|
+
if ( handshakeStatus != HandshakeStatus.NEED_UNWRAP || (!flush(netOutBuffer)) ) {
|
125
|
+
//should actually return OP_READ if we have NEED_UNWRAP
|
126
|
+
return SelectionKey.OP_WRITE;
|
127
|
+
}
|
128
|
+
//fall down to NEED_UNWRAP on the same call, will result in a
|
129
|
+
//BUFFER_UNDERFLOW if it needs data
|
130
|
+
}
|
131
|
+
//$FALL-THROUGH$
|
132
|
+
case NEED_UNWRAP: {
|
133
|
+
//perform the unwrap function
|
134
|
+
handshake = handshakeUnwrap(read);
|
135
|
+
if ( handshake.getStatus() == Status.OK ) {
|
136
|
+
if (handshakeStatus == HandshakeStatus.NEED_TASK)
|
137
|
+
handshakeStatus = tasks();
|
138
|
+
} else if ( handshake.getStatus() == Status.BUFFER_UNDERFLOW ){
|
139
|
+
//read more data, reregister for OP_READ
|
140
|
+
return SelectionKey.OP_READ;
|
141
|
+
} else {
|
142
|
+
throw new IOException("Invalid handshake status:"+handshakeStatus+" during handshake UNWRAP.");
|
143
|
+
}//switch
|
144
|
+
break;
|
145
|
+
}
|
146
|
+
case NEED_TASK: {
|
147
|
+
handshakeStatus = tasks();
|
148
|
+
break;
|
149
|
+
}
|
150
|
+
default: throw new IllegalStateException("Invalid handshake status:"+handshakeStatus);
|
151
|
+
}//switch
|
152
|
+
}//while
|
153
|
+
//return 0 if we are complete, otherwise reregister for any activity that
|
154
|
+
//would cause this method to be called again.
|
155
|
+
return handshakeComplete?0:(SelectionKey.OP_WRITE|SelectionKey.OP_READ);
|
156
|
+
}
|
157
|
+
|
158
|
+
|
159
|
+
/**
|
160
|
+
* Performs the WRAP function
|
161
|
+
* @param doWrite boolean
|
162
|
+
* @return SSLEngineResult
|
163
|
+
* @throws IOException
|
164
|
+
*/
|
165
|
+
private SSLEngineResult handshakeWrap(boolean doWrite) throws IOException {
|
166
|
+
//this should never be called with a network buffer that contains data
|
167
|
+
//so we can clear it here.
|
168
|
+
netOutBuffer.clear();
|
169
|
+
//perform the wrap
|
170
|
+
SSLEngineResult result = sslEngine.wrap(emptyBuf, netOutBuffer);
|
171
|
+
//prepare the results to be written
|
172
|
+
netOutBuffer.flip();
|
173
|
+
//set the status
|
174
|
+
handshakeStatus = result.getHandshakeStatus();
|
175
|
+
//optimization, if we do have a writable channel, write it now
|
176
|
+
if ( doWrite ) flush(netOutBuffer);
|
177
|
+
return result;
|
178
|
+
}
|
179
|
+
|
180
|
+
/**
|
181
|
+
* Perform handshake unwrap
|
182
|
+
* @param doread boolean
|
183
|
+
* @return SSLEngineResult
|
184
|
+
* @throws IOException
|
185
|
+
*/
|
186
|
+
private SSLEngineResult handshakeUnwrap(boolean doread) throws IOException {
|
187
|
+
|
188
|
+
if (netInBuffer.position() == netInBuffer.limit()) {
|
189
|
+
//clear the buffer if we have emptied it out on data
|
190
|
+
netInBuffer.clear();
|
191
|
+
}
|
192
|
+
if ( doread ) {
|
193
|
+
//if we have data to read, read it
|
194
|
+
int read = channel.read(netInBuffer);
|
195
|
+
if (read == -1) throw new IOException("EOF encountered during handshake.");
|
196
|
+
}
|
197
|
+
SSLEngineResult result;
|
198
|
+
boolean cont = false;
|
199
|
+
//loop while we can perform pure SSLEngine data
|
200
|
+
do {
|
201
|
+
//prepare the buffer with the incoming data
|
202
|
+
netInBuffer.flip();
|
203
|
+
//call unwrap
|
204
|
+
result = sslEngine.unwrap(netInBuffer, anotherBuffer);
|
205
|
+
//compact the buffer, this is an optional method, wonder what would happen if we didn't
|
206
|
+
netInBuffer.compact();
|
207
|
+
//read in the status
|
208
|
+
handshakeStatus = result.getHandshakeStatus();
|
209
|
+
if ( result.getStatus() == SSLEngineResult.Status.OK &&
|
210
|
+
result.getHandshakeStatus() == HandshakeStatus.NEED_TASK ) {
|
211
|
+
//execute tasks if we need to
|
212
|
+
handshakeStatus = tasks();
|
213
|
+
}
|
214
|
+
//perform another unwrap?
|
215
|
+
cont = result.getStatus() == SSLEngineResult.Status.OK &&
|
216
|
+
handshakeStatus == HandshakeStatus.NEED_UNWRAP;
|
217
|
+
}while ( cont );
|
218
|
+
return result;
|
219
|
+
}
|
220
|
+
|
221
|
+
/**
|
222
|
+
* Executes all the tasks needed on the same thread.
|
223
|
+
* @return HandshakeStatus
|
224
|
+
*/
|
225
|
+
private SSLEngineResult.HandshakeStatus tasks() {
|
226
|
+
Runnable r = null;
|
227
|
+
while ( (r = sslEngine.getDelegatedTask()) != null) {
|
228
|
+
r.run();
|
229
|
+
}
|
230
|
+
return sslEngine.getHandshakeStatus();
|
231
|
+
}
|
232
|
+
|
233
|
+
protected boolean flush(ByteBuffer buf) throws IOException {
|
234
|
+
int remaining = buf.remaining();
|
235
|
+
if ( remaining > 0 ) {
|
236
|
+
int written = channel.write(buf);
|
237
|
+
return written >= remaining;
|
238
|
+
}else {
|
239
|
+
return true;
|
240
|
+
}
|
241
|
+
}
|
242
|
+
|
243
|
+
public javax.security.cert.X509Certificate getPeerCert() throws SSLPeerUnverifiedException {
|
244
|
+
return sslEngine.getSession().getPeerCertificateChain()[0];
|
245
|
+
}
|
246
|
+
|
247
|
+
public int write(ByteBuffer src) throws IOException {
|
248
|
+
if (!flush(netOutBuffer)) return 0;
|
249
|
+
|
250
|
+
netOutBuffer.clear();
|
251
|
+
|
252
|
+
SSLEngineResult result = sslEngine.wrap(src, netOutBuffer);
|
253
|
+
int written = result.bytesConsumed();
|
254
|
+
netOutBuffer.flip();
|
255
|
+
|
256
|
+
if (result.getStatus() == Status.OK) {
|
257
|
+
if (result.getHandshakeStatus() == HandshakeStatus.NEED_TASK)
|
258
|
+
tasks();
|
259
|
+
} else {
|
260
|
+
throw new IOException("Unable to wrap data, invalid engine state: " +result.getStatus());
|
261
|
+
}
|
262
|
+
|
263
|
+
//force a flush
|
264
|
+
flush(netOutBuffer);
|
265
|
+
|
266
|
+
return written;
|
267
|
+
}
|
268
|
+
|
269
|
+
public int read(ByteBuffer dst) throws IOException {
|
270
|
+
//did we finish our handshake?
|
271
|
+
if (!handshakeComplete) throw new IllegalStateException("Handshake incomplete, you must complete handshake before reading data.");
|
272
|
+
|
273
|
+
//read from the network
|
274
|
+
int netread = channel.read(netInBuffer);
|
275
|
+
//did we reach EOF? if so send EOF up one layer.
|
276
|
+
if (netread == -1) return -1;
|
277
|
+
|
278
|
+
//the data read
|
279
|
+
int read = 0;
|
280
|
+
//the SSL engine result
|
281
|
+
SSLEngineResult unwrap;
|
282
|
+
do {
|
283
|
+
//prepare the buffer
|
284
|
+
netInBuffer.flip();
|
285
|
+
//unwrap the data
|
286
|
+
unwrap = sslEngine.unwrap(netInBuffer, dst);
|
287
|
+
//compact the buffer
|
288
|
+
netInBuffer.compact();
|
289
|
+
|
290
|
+
if ( unwrap.getStatus()==Status.OK || unwrap.getStatus()==Status.BUFFER_UNDERFLOW ) {
|
291
|
+
//we did receive some data, add it to our total
|
292
|
+
read += unwrap.bytesProduced();
|
293
|
+
//perform any tasks if needed
|
294
|
+
if (unwrap.getHandshakeStatus() == HandshakeStatus.NEED_TASK) tasks();
|
295
|
+
//if we need more network data, then bail out for now.
|
296
|
+
if ( unwrap.getStatus() == Status.BUFFER_UNDERFLOW ) break;
|
297
|
+
}else if ( unwrap.getStatus()==Status.BUFFER_OVERFLOW && read>0 ) {
|
298
|
+
//buffer overflow can happen, if we have read data, then
|
299
|
+
//empty out the dst buffer before we do another read
|
300
|
+
break;
|
301
|
+
}else {
|
302
|
+
//here we should trap BUFFER_OVERFLOW and call expand on the buffer
|
303
|
+
//for now, throw an exception, as we initialized the buffers
|
304
|
+
//in the constructor
|
305
|
+
throw new IOException("Unable to unwrap data, invalid status: " + unwrap.getStatus());
|
306
|
+
}
|
307
|
+
} while ( (netInBuffer.position() != 0)); //continue to unwrapping as long as the input buffer has stuff
|
308
|
+
return (read);
|
309
|
+
}
|
310
|
+
|
311
|
+
}
|
data/lib/em/buftok.rb
ADDED
@@ -0,0 +1,110 @@
|
|
1
|
+
# BufferedTokenizer takes a delimiter upon instantiation, or acts line-based
|
2
|
+
# by default. It allows input to be spoon-fed from some outside source which
|
3
|
+
# receives arbitrary length datagrams which may-or-may-not contain the token
|
4
|
+
# by which entities are delimited.
|
5
|
+
#
|
6
|
+
# By default, new BufferedTokenizers will operate on lines delimited by "\n" by default
|
7
|
+
# or allow you to specify any delimiter token you so choose, which will then
|
8
|
+
# be used by String#split to tokenize the input data
|
9
|
+
#
|
10
|
+
# @example Using BufferedTokernizer to parse lines out of incoming data
|
11
|
+
#
|
12
|
+
# module LineBufferedConnection
|
13
|
+
# def receive_data(data)
|
14
|
+
# (@buffer ||= BufferedTokenizer.new).extract(data).each do |line|
|
15
|
+
# receive_line(line)
|
16
|
+
# end
|
17
|
+
# end
|
18
|
+
# end
|
19
|
+
#
|
20
|
+
# @author Tony Arcieri
|
21
|
+
# @author Martin Emde
|
22
|
+
class BufferedTokenizer
|
23
|
+
# @param [String] delimiter
|
24
|
+
# @param [Integer] size_limit
|
25
|
+
def initialize(delimiter = "\n", size_limit = nil)
|
26
|
+
@delimiter = delimiter
|
27
|
+
@size_limit = size_limit
|
28
|
+
|
29
|
+
# The input buffer is stored as an array. This is by far the most efficient
|
30
|
+
# approach given language constraints (in C a linked list would be a more
|
31
|
+
# appropriate data structure). Segments of input data are stored in a list
|
32
|
+
# which is only joined when a token is reached, substantially reducing the
|
33
|
+
# number of objects required for the operation.
|
34
|
+
@input = []
|
35
|
+
|
36
|
+
# Size of the input buffer
|
37
|
+
@input_size = 0
|
38
|
+
end
|
39
|
+
|
40
|
+
# Extract takes an arbitrary string of input data and returns an array of
|
41
|
+
# tokenized entities, provided there were any available to extract.
|
42
|
+
#
|
43
|
+
# @example
|
44
|
+
#
|
45
|
+
# tokenizer.extract(data).
|
46
|
+
# map { |entity| Decode(entity) }.each { ... }
|
47
|
+
#
|
48
|
+
# @param [String] data
|
49
|
+
def extract(data)
|
50
|
+
# Extract token-delimited entities from the input string with the split command.
|
51
|
+
# There's a bit of craftiness here with the -1 parameter. Normally split would
|
52
|
+
# behave no differently regardless of if the token lies at the very end of the
|
53
|
+
# input buffer or not (i.e. a literal edge case) Specifying -1 forces split to
|
54
|
+
# return "" in this case, meaning that the last entry in the list represents a
|
55
|
+
# new segment of data where the token has not been encountered
|
56
|
+
entities = data.split @delimiter, -1
|
57
|
+
|
58
|
+
# Check to see if the buffer has exceeded capacity, if we're imposing a limit
|
59
|
+
if @size_limit
|
60
|
+
raise 'input buffer full' if @input_size + entities.first.size > @size_limit
|
61
|
+
@input_size += entities.first.size
|
62
|
+
end
|
63
|
+
|
64
|
+
# Move the first entry in the resulting array into the input buffer. It represents
|
65
|
+
# the last segment of a token-delimited entity unless it's the only entry in the list.
|
66
|
+
@input << entities.shift
|
67
|
+
|
68
|
+
# If the resulting array from the split is empty, the token was not encountered
|
69
|
+
# (not even at the end of the buffer). Since we've encountered no token-delimited
|
70
|
+
# entities this go-around, return an empty array.
|
71
|
+
return [] if entities.empty?
|
72
|
+
|
73
|
+
# At this point, we've hit a token, or potentially multiple tokens. Now we can bring
|
74
|
+
# together all the data we've buffered from earlier calls without hitting a token,
|
75
|
+
# and add it to our list of discovered entities.
|
76
|
+
entities.unshift @input.join
|
77
|
+
|
78
|
+
# Now that we've hit a token, joined the input buffer and added it to the entities
|
79
|
+
# list, we can go ahead and clear the input buffer. All of the segments that were
|
80
|
+
# stored before the join can now be garbage collected.
|
81
|
+
@input.clear
|
82
|
+
|
83
|
+
# The last entity in the list is not token delimited, however, thanks to the -1
|
84
|
+
# passed to split. It represents the beginning of a new list of as-yet-untokenized
|
85
|
+
# data, so we add it to the start of the list.
|
86
|
+
@input << entities.pop
|
87
|
+
|
88
|
+
# Set the new input buffer size, provided we're keeping track
|
89
|
+
@input_size = @input.first.size if @size_limit
|
90
|
+
|
91
|
+
# Now we're left with the list of extracted token-delimited entities we wanted
|
92
|
+
# in the first place. Hooray!
|
93
|
+
entities
|
94
|
+
end
|
95
|
+
|
96
|
+
# Flush the contents of the input buffer, i.e. return the input buffer even though
|
97
|
+
# a token has not yet been encountered.
|
98
|
+
#
|
99
|
+
# @return [String]
|
100
|
+
def flush
|
101
|
+
buffer = @input.join
|
102
|
+
@input.clear
|
103
|
+
buffer
|
104
|
+
end
|
105
|
+
|
106
|
+
# @return [Boolean]
|
107
|
+
def empty?
|
108
|
+
@input.empty?
|
109
|
+
end
|
110
|
+
end
|
data/lib/em/callback.rb
ADDED
@@ -0,0 +1,58 @@
|
|
1
|
+
module EventMachine
|
2
|
+
# Utility method for coercing arguments to an object that responds to :call.
|
3
|
+
# Accepts an object and a method name to send to, or a block, or an object
|
4
|
+
# that responds to :call.
|
5
|
+
#
|
6
|
+
# @example EventMachine.Callback used with a block. Returns that block.
|
7
|
+
#
|
8
|
+
# cb = EventMachine.Callback do |msg|
|
9
|
+
# puts(msg)
|
10
|
+
# end
|
11
|
+
# # returned object is a callable
|
12
|
+
# cb.call('hello world')
|
13
|
+
#
|
14
|
+
#
|
15
|
+
# @example EventMachine.Callback used with an object (to be more specific, class object) and a method name, returns an object that responds to #call
|
16
|
+
#
|
17
|
+
# cb = EventMachine.Callback(Object, :puts)
|
18
|
+
# # returned object is a callable that delegates to Kernel#puts (in this case Object.puts)
|
19
|
+
# cb.call('hello world')
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# @example EventMachine.Callback used with an object that responds to #call. Returns the argument.
|
23
|
+
#
|
24
|
+
# cb = EventMachine.Callback(proc{ |msg| puts(msg) })
|
25
|
+
# # returned object is a callable
|
26
|
+
# cb.call('hello world')
|
27
|
+
#
|
28
|
+
#
|
29
|
+
# @overload Callback(object, method)
|
30
|
+
# Wraps `method` invocation on `object` into an object that responds to #call that proxies all the arguments to that method
|
31
|
+
# @param [Object] Object to invoke method on
|
32
|
+
# @param [Symbol] Method name
|
33
|
+
# @return [<#call>] An object that responds to #call that takes any number of arguments and invokes method on object with those arguments
|
34
|
+
#
|
35
|
+
# @overload Callback(object)
|
36
|
+
# Returns callable object as is, without any coercion
|
37
|
+
# @param [<#call>] An object that responds to #call
|
38
|
+
# @return [<#call>] Its argument
|
39
|
+
#
|
40
|
+
# @overload Callback(&block)
|
41
|
+
# Returns block passed to it without any coercion
|
42
|
+
# @return [<#call>] Block passed to this method
|
43
|
+
#
|
44
|
+
# @raise [ArgumentError] When argument doesn't respond to #call, method name is missing or when invoked without arguments and block isn't given
|
45
|
+
#
|
46
|
+
# @return [<#call>]
|
47
|
+
def self.Callback(object = nil, method = nil, &blk)
|
48
|
+
if object && method
|
49
|
+
lambda { |*args| object.__send__ method, *args }
|
50
|
+
else
|
51
|
+
if object.respond_to? :call
|
52
|
+
object
|
53
|
+
else
|
54
|
+
blk || raise(ArgumentError)
|
55
|
+
end # if
|
56
|
+
end # if
|
57
|
+
end # self.Callback
|
58
|
+
end # EventMachine
|