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,26 @@
|
|
1
|
+
package com.rubyeventmachine;
|
2
|
+
|
3
|
+
public enum EventCode {
|
4
|
+
EM_TIMER_FIRED(100),
|
5
|
+
EM_CONNECTION_READ(101),
|
6
|
+
EM_CONNECTION_UNBOUND(102),
|
7
|
+
EM_CONNECTION_ACCEPTED(103),
|
8
|
+
EM_CONNECTION_COMPLETED(104),
|
9
|
+
EM_LOOPBREAK_SIGNAL(105),
|
10
|
+
EM_CONNECTION_NOTIFY_READABLE(106),
|
11
|
+
EM_CONNECTION_NOTIFY_WRITABLE(107),
|
12
|
+
EM_SSL_HANDSHAKE_COMPLETED(108),
|
13
|
+
EM_SSL_VERIFY(109),
|
14
|
+
EM_PROXY_TARGET_UNBOUND(110),
|
15
|
+
EM_PROXY_COMPLETED(111);
|
16
|
+
|
17
|
+
private final int intValue;
|
18
|
+
|
19
|
+
EventCode(int intValue) {
|
20
|
+
this.intValue = intValue;
|
21
|
+
}
|
22
|
+
|
23
|
+
public int intValue() {
|
24
|
+
return intValue;
|
25
|
+
}
|
26
|
+
}
|
@@ -1,70 +1,130 @@
|
|
1
1
|
/**
|
2
2
|
* $Id$
|
3
|
-
*
|
3
|
+
*
|
4
4
|
* Author:: Francis Cianfrocca (gmail: blackhedd)
|
5
5
|
* Homepage:: http://rubyeventmachine.com
|
6
6
|
* Date:: 15 Jul 2007
|
7
|
-
*
|
7
|
+
*
|
8
8
|
* See EventMachine and EventMachine::Connection for documentation and
|
9
9
|
* usage examples.
|
10
|
-
*
|
10
|
+
*
|
11
11
|
*
|
12
12
|
*----------------------------------------------------------------------------
|
13
13
|
*
|
14
14
|
* Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
15
15
|
* Gmail: blackhedd
|
16
|
-
*
|
16
|
+
*
|
17
17
|
* This program is free software; you can redistribute it and/or modify
|
18
18
|
* it under the terms of either: 1) the GNU General Public License
|
19
19
|
* as published by the Free Software Foundation; either version 2 of the
|
20
20
|
* License, or (at your option) any later version; or 2) Ruby's License.
|
21
|
-
*
|
21
|
+
*
|
22
22
|
* See the file COPYING for complete licensing information.
|
23
23
|
*
|
24
24
|
*---------------------------------------------------------------------------
|
25
25
|
*
|
26
|
-
*
|
26
|
+
*
|
27
27
|
*/
|
28
28
|
|
29
|
-
|
30
29
|
package com.rubyeventmachine;
|
31
30
|
|
32
31
|
import java.nio.ByteBuffer;
|
33
32
|
import java.io.IOException;
|
34
33
|
import java.nio.channels.ClosedChannelException;
|
35
|
-
|
36
|
-
|
37
|
-
|
38
|
-
|
39
|
-
|
40
|
-
|
41
|
-
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
34
|
+
import java.nio.channels.Selector;
|
35
|
+
import java.util.LinkedList;
|
36
|
+
|
37
|
+
public abstract class EventableChannel<OutboundPacketType> {
|
38
|
+
protected final long binding;
|
39
|
+
protected final Selector selector;
|
40
|
+
protected final LinkedList<OutboundPacketType> outboundQ;
|
41
|
+
protected final EventCallback callback;
|
42
|
+
private final ByteBuffer readBuffer;
|
43
|
+
|
44
|
+
public EventableChannel(long binding, Selector selector,
|
45
|
+
EventCallback callback) {
|
46
|
+
this.binding = binding;
|
47
|
+
this.selector = selector;
|
48
|
+
this.callback = callback;
|
49
|
+
this.outboundQ = new LinkedList<OutboundPacketType>();
|
50
|
+
this.readBuffer = ByteBuffer.allocate(32*1024); // don't use a direct buffer. Ruby doesn't seem to like them.
|
51
|
+
}
|
52
|
+
|
53
|
+
public abstract void scheduleOutboundData(ByteBuffer bb);
|
54
|
+
|
55
|
+
public abstract void scheduleOutboundDatagram(ByteBuffer bb,
|
56
|
+
String recipAddress, int recipPort);
|
57
|
+
|
58
|
+
public abstract boolean scheduleClose(boolean afterWriting);
|
59
|
+
|
60
|
+
public abstract void startTls();
|
61
|
+
|
62
|
+
public long getBinding() {
|
63
|
+
return binding;
|
64
|
+
}
|
65
|
+
|
66
|
+
public abstract void register() throws ClosedChannelException;
|
67
|
+
|
68
|
+
/**
|
69
|
+
* This is called by the reactor after it finishes running. The idea is to
|
70
|
+
* free network resources.
|
71
|
+
*/
|
72
|
+
public abstract void close();
|
73
|
+
|
74
|
+
public void setCommInactivityTimeout (long seconds) {
|
75
|
+
// TODO
|
76
|
+
System.out.println ("SET COMM INACTIVITY UNIMPLEMENTED IN JRUBY" + seconds);
|
77
|
+
}
|
78
|
+
|
79
|
+
public abstract Object[] getPeerName();
|
80
|
+
|
81
|
+
public abstract Object[] getSockName();
|
82
|
+
|
83
|
+
public abstract boolean isWatchOnly();
|
84
|
+
|
85
|
+
public abstract boolean isNotifyReadable();
|
86
|
+
|
87
|
+
public abstract boolean isNotifyWritable();
|
88
|
+
|
89
|
+
protected abstract boolean handshakeNeeded();
|
90
|
+
protected abstract boolean performHandshake();
|
91
|
+
|
92
|
+
protected abstract void readInboundData(ByteBuffer dst) throws IOException;
|
93
|
+
|
94
|
+
public boolean read() {
|
95
|
+
if (handshakeNeeded()) {
|
96
|
+
return performHandshake();
|
97
|
+
} else if (isWatchOnly() && isNotifyReadable()) {
|
98
|
+
callback.trigger(binding, EventCode.EM_CONNECTION_NOTIFY_READABLE, null, 0);
|
99
|
+
} else {
|
100
|
+
readBuffer.clear();
|
101
|
+
|
102
|
+
try {
|
103
|
+
readInboundData(readBuffer);
|
104
|
+
readBuffer.flip();
|
105
|
+
if (readBuffer.limit() > 0)
|
106
|
+
callback.trigger(binding, EventCode.EM_CONNECTION_READ, readBuffer, 0);
|
107
|
+
} catch (IOException e) {
|
108
|
+
return false;
|
109
|
+
}
|
110
|
+
}
|
111
|
+
return true;
|
112
|
+
}
|
113
|
+
|
114
|
+
protected abstract boolean writeOutboundData() throws IOException;
|
115
|
+
|
116
|
+
public boolean write() {
|
117
|
+
if (handshakeNeeded()) {
|
118
|
+
return performHandshake();
|
119
|
+
} else if (isWatchOnly() || isNotifyWritable()) {
|
120
|
+
callback.trigger(binding, EventCode.EM_CONNECTION_NOTIFY_WRITABLE, null, 0);
|
121
|
+
} else {
|
122
|
+
try {
|
123
|
+
return writeOutboundData();
|
124
|
+
} catch (IOException e) {
|
125
|
+
return false;
|
126
|
+
}
|
127
|
+
}
|
128
|
+
return true;
|
129
|
+
}
|
70
130
|
}
|
@@ -1,29 +1,29 @@
|
|
1
1
|
/**
|
2
2
|
* $Id$
|
3
|
-
*
|
3
|
+
*
|
4
4
|
* Author:: Francis Cianfrocca (gmail: blackhedd)
|
5
5
|
* Homepage:: http://rubyeventmachine.com
|
6
6
|
* Date:: 15 Jul 2007
|
7
|
-
*
|
7
|
+
*
|
8
8
|
* See EventMachine and EventMachine::Connection for documentation and
|
9
9
|
* usage examples.
|
10
|
-
*
|
10
|
+
*
|
11
11
|
*
|
12
12
|
*----------------------------------------------------------------------------
|
13
13
|
*
|
14
14
|
* Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
|
15
15
|
* Gmail: blackhedd
|
16
|
-
*
|
16
|
+
*
|
17
17
|
* This program is free software; you can redistribute it and/or modify
|
18
18
|
* it under the terms of either: 1) the GNU General Public License
|
19
19
|
* as published by the Free Software Foundation; either version 2 of the
|
20
20
|
* License, or (at your option) any later version; or 2) Ruby's License.
|
21
|
-
*
|
21
|
+
*
|
22
22
|
* See the file COPYING for complete licensing information.
|
23
23
|
*
|
24
24
|
*---------------------------------------------------------------------------
|
25
25
|
*
|
26
|
-
*
|
26
|
+
*
|
27
27
|
*/
|
28
28
|
|
29
29
|
|
@@ -34,162 +34,147 @@ import java.nio.channels.ClosedChannelException;
|
|
34
34
|
import java.nio.channels.SelectionKey;
|
35
35
|
import java.nio.channels.Selector;
|
36
36
|
import java.nio.channels.DatagramChannel;
|
37
|
-
import java.util.LinkedList;
|
38
37
|
import java.io.*;
|
39
38
|
import java.net.*;
|
40
39
|
|
41
|
-
public class EventableDatagramChannel
|
42
|
-
|
43
|
-
|
44
|
-
|
45
|
-
|
46
|
-
|
47
|
-
|
48
|
-
|
49
|
-
|
50
|
-
|
51
|
-
|
52
|
-
|
53
|
-
|
54
|
-
|
55
|
-
|
56
|
-
|
57
|
-
|
58
|
-
|
59
|
-
|
60
|
-
|
61
|
-
|
62
|
-
|
63
|
-
|
64
|
-
|
65
|
-
|
66
|
-
|
67
|
-
|
68
|
-
|
69
|
-
|
70
|
-
|
71
|
-
|
72
|
-
|
73
|
-
|
74
|
-
|
75
|
-
|
76
|
-
|
77
|
-
|
78
|
-
|
79
|
-
|
80
|
-
|
81
|
-
|
82
|
-
|
83
|
-
|
84
|
-
|
85
|
-
|
86
|
-
|
87
|
-
|
88
|
-
|
89
|
-
|
90
|
-
|
91
|
-
|
92
|
-
|
93
|
-
|
94
|
-
|
95
|
-
|
96
|
-
|
97
|
-
|
98
|
-
|
99
|
-
|
100
|
-
|
101
|
-
|
102
|
-
|
103
|
-
|
104
|
-
|
105
|
-
|
106
|
-
|
107
|
-
|
108
|
-
|
109
|
-
|
110
|
-
|
111
|
-
|
112
|
-
|
113
|
-
|
114
|
-
|
115
|
-
|
116
|
-
|
117
|
-
|
118
|
-
|
119
|
-
|
120
|
-
|
121
|
-
|
122
|
-
|
123
|
-
|
124
|
-
|
125
|
-
|
126
|
-
|
127
|
-
|
128
|
-
|
129
|
-
|
130
|
-
|
131
|
-
|
132
|
-
|
133
|
-
|
134
|
-
|
135
|
-
|
136
|
-
|
137
|
-
|
138
|
-
|
139
|
-
|
140
|
-
|
141
|
-
|
142
|
-
|
143
|
-
|
144
|
-
|
145
|
-
|
146
|
-
|
147
|
-
|
148
|
-
|
149
|
-
|
150
|
-
|
151
|
-
|
152
|
-
|
153
|
-
|
154
|
-
|
155
|
-
|
156
|
-
|
157
|
-
|
158
|
-
|
159
|
-
|
160
|
-
|
161
|
-
|
162
|
-
|
163
|
-
|
164
|
-
|
165
|
-
|
166
|
-
|
167
|
-
|
168
|
-
|
169
|
-
|
170
|
-
|
171
|
-
|
172
|
-
|
173
|
-
|
174
|
-
|
175
|
-
|
176
|
-
|
177
|
-
|
178
|
-
|
179
|
-
|
180
|
-
|
181
|
-
} else {
|
182
|
-
return null;
|
183
|
-
}
|
184
|
-
}
|
185
|
-
|
186
|
-
public Object[] getSockName () {
|
187
|
-
DatagramSocket socket = channel.socket();
|
188
|
-
return new Object[]{ socket.getLocalPort(),
|
189
|
-
socket.getLocalAddress().getHostAddress() };
|
190
|
-
}
|
191
|
-
|
192
|
-
public boolean isWatchOnly() { return false; }
|
193
|
-
public boolean isNotifyReadable() { return false; }
|
194
|
-
public boolean isNotifyWritable() { return false; }
|
40
|
+
public class EventableDatagramChannel extends EventableChannel<DatagramPacket> {
|
41
|
+
|
42
|
+
DatagramChannel channel;
|
43
|
+
boolean bCloseScheduled;
|
44
|
+
SocketAddress returnAddress;
|
45
|
+
|
46
|
+
public EventableDatagramChannel (DatagramChannel dc, long _binding, Selector sel, EventCallback callback) throws ClosedChannelException {
|
47
|
+
super(_binding, sel, callback);
|
48
|
+
channel = dc;
|
49
|
+
bCloseScheduled = false;
|
50
|
+
|
51
|
+
dc.register(selector, SelectionKey.OP_READ, this);
|
52
|
+
}
|
53
|
+
|
54
|
+
public void scheduleOutboundData (ByteBuffer bb) {
|
55
|
+
try {
|
56
|
+
if ((!bCloseScheduled) && (bb.remaining() > 0)) {
|
57
|
+
outboundQ.addLast(new DatagramPacket(bb, returnAddress));
|
58
|
+
channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this);
|
59
|
+
}
|
60
|
+
} catch (ClosedChannelException e) {
|
61
|
+
throw new RuntimeException ("no outbound data");
|
62
|
+
}
|
63
|
+
}
|
64
|
+
|
65
|
+
public void scheduleOutboundDatagram (ByteBuffer bb, String recipAddress, int recipPort) {
|
66
|
+
try {
|
67
|
+
if ((!bCloseScheduled) && (bb.remaining() > 0)) {
|
68
|
+
outboundQ.addLast(new DatagramPacket (bb, new InetSocketAddress (recipAddress, recipPort)));
|
69
|
+
channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this);
|
70
|
+
}
|
71
|
+
} catch (ClosedChannelException e) {
|
72
|
+
throw new RuntimeException ("no outbound data");
|
73
|
+
}
|
74
|
+
}
|
75
|
+
|
76
|
+
public boolean scheduleClose (boolean afterWriting) {
|
77
|
+
System.out.println ("NOT SCHEDULING CLOSE ON DATAGRAM");
|
78
|
+
return false;
|
79
|
+
}
|
80
|
+
|
81
|
+
public void startTls() {
|
82
|
+
throw new RuntimeException ("TLS is unimplemented on this Channel");
|
83
|
+
}
|
84
|
+
|
85
|
+
public void register() throws ClosedChannelException {
|
86
|
+
// TODO
|
87
|
+
}
|
88
|
+
|
89
|
+
/**
|
90
|
+
* Terminate with extreme prejudice. Don't assume there will be another pass through
|
91
|
+
* the reactor core.
|
92
|
+
*/
|
93
|
+
public void close() {
|
94
|
+
try {
|
95
|
+
channel.close();
|
96
|
+
} catch (IOException e) {
|
97
|
+
}
|
98
|
+
}
|
99
|
+
|
100
|
+
public void readInboundData (ByteBuffer dst) {
|
101
|
+
returnAddress = null;
|
102
|
+
try {
|
103
|
+
// If there is no datagram available (we're nonblocking after all),
|
104
|
+
// then channel.receive returns null.
|
105
|
+
returnAddress = channel.receive(dst);
|
106
|
+
} catch (IOException e) {
|
107
|
+
// probably a no-op. The caller will see the empty (or even partial) buffer
|
108
|
+
// and presumably do the right thing.
|
109
|
+
}
|
110
|
+
}
|
111
|
+
|
112
|
+
protected boolean writeOutboundData() {
|
113
|
+
while (!outboundQ.isEmpty()) {
|
114
|
+
DatagramPacket p = outboundQ.getFirst();
|
115
|
+
int written = 0;
|
116
|
+
try {
|
117
|
+
// With a datagram socket, it's ok to send an empty buffer.
|
118
|
+
written = channel.send(p.bb, p.recipient);
|
119
|
+
}
|
120
|
+
catch (IOException e) {
|
121
|
+
return false;
|
122
|
+
}
|
123
|
+
|
124
|
+
/* Did we consume the whole outbound buffer? If yes, pop it off and
|
125
|
+
* keep looping. If no, the outbound network buffers are full, so break
|
126
|
+
* out of here. There's a flaw that affects outbound buffers that are intentionally
|
127
|
+
* empty. We can tell whether they got sent or not. So we assume they were.
|
128
|
+
* TODO: As implemented, this ALWAYS discards packets if they were at least
|
129
|
+
* partially written. This matches the behavior of the C++ EM. My judgment
|
130
|
+
* is that this is less surprising than fragmenting the data and sending multiple
|
131
|
+
* packets would be. I could be wrong, so this is subject to change.
|
132
|
+
*/
|
133
|
+
|
134
|
+
if ((written > 0) || (p.bb.remaining() == 0))
|
135
|
+
outboundQ.removeFirst();
|
136
|
+
else
|
137
|
+
break;
|
138
|
+
}
|
139
|
+
|
140
|
+
if (outboundQ.isEmpty()) {
|
141
|
+
try {
|
142
|
+
channel.register(selector, SelectionKey.OP_READ, this);
|
143
|
+
} catch (ClosedChannelException e) {}
|
144
|
+
}
|
145
|
+
|
146
|
+
// ALWAYS drain the outbound queue before triggering a connection close.
|
147
|
+
// If anyone wants to close immediately, they're responsible for clearing
|
148
|
+
// the outbound queue.
|
149
|
+
return (bCloseScheduled && outboundQ.isEmpty()) ? false : true;
|
150
|
+
}
|
151
|
+
|
152
|
+
public Object[] getPeerName () {
|
153
|
+
if (returnAddress != null) {
|
154
|
+
InetSocketAddress inetAddr = (InetSocketAddress) returnAddress;
|
155
|
+
return new Object[]{ inetAddr.getPort(), inetAddr.getHostName() };
|
156
|
+
} else {
|
157
|
+
return null;
|
158
|
+
}
|
159
|
+
}
|
160
|
+
|
161
|
+
public Object[] getSockName () {
|
162
|
+
DatagramSocket socket = channel.socket();
|
163
|
+
return new Object[]{ socket.getLocalPort(),
|
164
|
+
socket.getLocalAddress().getHostAddress() };
|
165
|
+
}
|
166
|
+
|
167
|
+
public boolean isWatchOnly() { return false; }
|
168
|
+
public boolean isNotifyReadable() { return false; }
|
169
|
+
public boolean isNotifyWritable() { return false; }
|
170
|
+
|
171
|
+
@Override
|
172
|
+
protected boolean handshakeNeeded() {
|
173
|
+
return false;
|
174
|
+
}
|
175
|
+
|
176
|
+
@Override
|
177
|
+
protected boolean performHandshake() {
|
178
|
+
return true;
|
179
|
+
}
|
195
180
|
}
|