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

Sign up to get free protection for your applications and to get access to all the features.
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
  }