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,7 @@
1
+ package com.rubyeventmachine;
2
+
3
+ import java.nio.ByteBuffer;
4
+
5
+ public interface EventCallback {
6
+ void trigger(long sig, EventCode eventType, ByteBuffer data, long data2);
7
+ }
@@ -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
- public interface EventableChannel {
37
-
38
- public void scheduleOutboundData (ByteBuffer bb);
39
-
40
- public void scheduleOutboundDatagram (ByteBuffer bb, String recipAddress, int recipPort);
41
-
42
- public boolean scheduleClose (boolean afterWriting);
43
-
44
- public void startTls();
45
-
46
- public long getBinding();
47
-
48
- public void readInboundData (ByteBuffer dst) throws IOException;
49
-
50
- public void register() throws ClosedChannelException;
51
-
52
- /**
53
- * This is called by the reactor after it finishes running.
54
- * The idea is to free network resources.
55
- */
56
- public void close();
57
-
58
- public boolean writeOutboundData() throws IOException;
59
-
60
- public void setCommInactivityTimeout (long seconds);
61
-
62
- public Object[] getPeerName();
63
- public Object[] getSockName();
64
-
65
- public boolean isWatchOnly();
66
-
67
- public boolean isNotifyReadable();
68
- public boolean isNotifyWritable();
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 implements EventableChannel {
42
-
43
- class Packet {
44
- public ByteBuffer bb;
45
- public SocketAddress recipient;
46
- public Packet (ByteBuffer _bb, SocketAddress _recipient) {
47
- bb = _bb;
48
- recipient = _recipient;
49
- }
50
- }
51
-
52
- DatagramChannel channel;
53
- long binding;
54
- Selector selector;
55
- boolean bCloseScheduled;
56
- LinkedList<Packet> outboundQ;
57
- SocketAddress returnAddress;
58
-
59
-
60
- public EventableDatagramChannel (DatagramChannel dc, long _binding, Selector sel) throws ClosedChannelException {
61
- channel = dc;
62
- binding = _binding;
63
- selector = sel;
64
- bCloseScheduled = false;
65
- outboundQ = new LinkedList<Packet>();
66
-
67
- dc.register(selector, SelectionKey.OP_READ, this);
68
- }
69
-
70
- public void scheduleOutboundData (ByteBuffer bb) {
71
- try {
72
- if ((!bCloseScheduled) && (bb.remaining() > 0)) {
73
- outboundQ.addLast(new Packet(bb, returnAddress));
74
- channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this);
75
- }
76
- } catch (ClosedChannelException e) {
77
- throw new RuntimeException ("no outbound data");
78
- }
79
- }
80
-
81
- public void scheduleOutboundDatagram (ByteBuffer bb, String recipAddress, int recipPort) {
82
- try {
83
- if ((!bCloseScheduled) && (bb.remaining() > 0)) {
84
- outboundQ.addLast(new Packet (bb, new InetSocketAddress (recipAddress, recipPort)));
85
- channel.register(selector, SelectionKey.OP_WRITE | SelectionKey.OP_READ, this);
86
- }
87
- } catch (ClosedChannelException e) {
88
- throw new RuntimeException ("no outbound data");
89
- }
90
- }
91
-
92
- public boolean scheduleClose (boolean afterWriting) {
93
- System.out.println ("NOT SCHEDULING CLOSE ON DATAGRAM");
94
- return false;
95
- }
96
-
97
- public void startTls() {
98
- throw new RuntimeException ("TLS is unimplemented on this Channel");
99
- }
100
-
101
- public long getBinding() {
102
- return binding;
103
- }
104
-
105
- public void register() throws ClosedChannelException {
106
- // TODO
107
- }
108
-
109
- /**
110
- * Terminate with extreme prejudice. Don't assume there will be another pass through
111
- * the reactor core.
112
- */
113
- public void close() {
114
- try {
115
- channel.close();
116
- } catch (IOException e) {
117
- }
118
- }
119
-
120
- public void readInboundData (ByteBuffer dst) {
121
- returnAddress = null;
122
- try {
123
- // If there is no datagram available (we're nonblocking after all),
124
- // then channel.receive returns null.
125
- returnAddress = channel.receive(dst);
126
- } catch (IOException e) {
127
- // probably a no-op. The caller will see the empty (or even partial) buffer
128
- // and presumably do the right thing.
129
- }
130
- }
131
-
132
- public boolean writeOutboundData() {
133
- while (!outboundQ.isEmpty()) {
134
- Packet p = outboundQ.getFirst();
135
- int written = 0;
136
- try {
137
- // With a datagram socket, it's ok to send an empty buffer.
138
- written = channel.send(p.bb, p.recipient);
139
- }
140
- catch (IOException e) {
141
- return false;
142
- }
143
-
144
- /* Did we consume the whole outbound buffer? If yes, pop it off and
145
- * keep looping. If no, the outbound network buffers are full, so break
146
- * out of here. There's a flaw that affects outbound buffers that are intentionally
147
- * empty. We can tell whether they got sent or not. So we assume they were.
148
- * TODO: As implemented, this ALWAYS discards packets if they were at least
149
- * partially written. This matches the behavior of the C++ EM. My judgment
150
- * is that this is less surprising than fragmenting the data and sending multiple
151
- * packets would be. I could be wrong, so this is subject to change.
152
- */
153
-
154
- if ((written > 0) || (p.bb.remaining() == 0))
155
- outboundQ.removeFirst();
156
- else
157
- break;
158
- }
159
-
160
- if (outboundQ.isEmpty()) {
161
- try {
162
- channel.register(selector, SelectionKey.OP_READ, this);
163
- } catch (ClosedChannelException e) {}
164
- }
165
-
166
- // ALWAYS drain the outbound queue before triggering a connection close.
167
- // If anyone wants to close immediately, they're responsible for clearing
168
- // the outbound queue.
169
- return (bCloseScheduled && outboundQ.isEmpty()) ? false : true;
170
- }
171
-
172
- public void setCommInactivityTimeout (long seconds) {
173
- // TODO
174
- System.out.println ("DATAGRAM: SET COMM INACTIVITY UNIMPLEMENTED " + seconds);
175
- }
176
-
177
- public Object[] getPeerName () {
178
- if (returnAddress != null) {
179
- InetSocketAddress inetAddr = (InetSocketAddress) returnAddress;
180
- return new Object[]{ inetAddr.getPort(), inetAddr.getHostName() };
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
  }