eventmachine-eventmachine 0.12.3

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 (121) hide show
  1. data/Rakefile +169 -0
  2. data/docs/COPYING +60 -0
  3. data/docs/ChangeLog +183 -0
  4. data/docs/DEFERRABLES +138 -0
  5. data/docs/EPOLL +141 -0
  6. data/docs/GNU +281 -0
  7. data/docs/INSTALL +15 -0
  8. data/docs/KEYBOARD +38 -0
  9. data/docs/LEGAL +25 -0
  10. data/docs/LIGHTWEIGHT_CONCURRENCY +72 -0
  11. data/docs/PURE_RUBY +77 -0
  12. data/docs/README +74 -0
  13. data/docs/RELEASE_NOTES +96 -0
  14. data/docs/SMTP +9 -0
  15. data/docs/SPAWNED_PROCESSES +93 -0
  16. data/docs/TODO +10 -0
  17. data/ext/binder.cpp +126 -0
  18. data/ext/binder.h +48 -0
  19. data/ext/cmain.cpp +530 -0
  20. data/ext/cplusplus.cpp +172 -0
  21. data/ext/ed.cpp +1473 -0
  22. data/ext/ed.h +361 -0
  23. data/ext/em.cpp +1895 -0
  24. data/ext/em.h +170 -0
  25. data/ext/emwin.cpp +300 -0
  26. data/ext/emwin.h +94 -0
  27. data/ext/epoll.cpp +26 -0
  28. data/ext/epoll.h +25 -0
  29. data/ext/eventmachine.h +90 -0
  30. data/ext/eventmachine_cpp.h +94 -0
  31. data/ext/extconf.rb +150 -0
  32. data/ext/files.cpp +94 -0
  33. data/ext/files.h +65 -0
  34. data/ext/kb.cpp +368 -0
  35. data/ext/page.cpp +107 -0
  36. data/ext/page.h +51 -0
  37. data/ext/pipe.cpp +327 -0
  38. data/ext/project.h +119 -0
  39. data/ext/rubymain.cpp +683 -0
  40. data/ext/sigs.cpp +89 -0
  41. data/ext/sigs.h +32 -0
  42. data/ext/ssl.cpp +408 -0
  43. data/ext/ssl.h +86 -0
  44. data/java/src/com/rubyeventmachine/Application.java +196 -0
  45. data/java/src/com/rubyeventmachine/Connection.java +74 -0
  46. data/java/src/com/rubyeventmachine/ConnectionFactory.java +37 -0
  47. data/java/src/com/rubyeventmachine/DefaultConnectionFactory.java +46 -0
  48. data/java/src/com/rubyeventmachine/EmReactor.java +408 -0
  49. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  50. data/java/src/com/rubyeventmachine/EventableChannel.java +57 -0
  51. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +171 -0
  52. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +244 -0
  53. data/java/src/com/rubyeventmachine/PeriodicTimer.java +38 -0
  54. data/java/src/com/rubyeventmachine/Timer.java +54 -0
  55. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +108 -0
  56. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +124 -0
  57. data/java/src/com/rubyeventmachine/tests/EMTest.java +80 -0
  58. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +53 -0
  59. data/java/src/com/rubyeventmachine/tests/TestServers.java +74 -0
  60. data/java/src/com/rubyeventmachine/tests/TestTimers.java +89 -0
  61. data/lib/em/deferrable.rb +208 -0
  62. data/lib/em/eventable.rb +39 -0
  63. data/lib/em/future.rb +62 -0
  64. data/lib/em/messages.rb +66 -0
  65. data/lib/em/processes.rb +68 -0
  66. data/lib/em/spawnable.rb +88 -0
  67. data/lib/em/streamer.rb +112 -0
  68. data/lib/eventmachine.rb +1763 -0
  69. data/lib/eventmachine_version.rb +31 -0
  70. data/lib/evma.rb +32 -0
  71. data/lib/evma/callback.rb +32 -0
  72. data/lib/evma/container.rb +75 -0
  73. data/lib/evma/factory.rb +77 -0
  74. data/lib/evma/protocol.rb +87 -0
  75. data/lib/evma/reactor.rb +48 -0
  76. data/lib/jeventmachine.rb +137 -0
  77. data/lib/pr_eventmachine.rb +1011 -0
  78. data/lib/protocols/buftok.rb +127 -0
  79. data/lib/protocols/header_and_content.rb +129 -0
  80. data/lib/protocols/httpcli2.rb +794 -0
  81. data/lib/protocols/httpclient.rb +270 -0
  82. data/lib/protocols/line_and_text.rb +122 -0
  83. data/lib/protocols/linetext2.rb +163 -0
  84. data/lib/protocols/postgres.rb +261 -0
  85. data/lib/protocols/saslauth.rb +179 -0
  86. data/lib/protocols/smtpclient.rb +308 -0
  87. data/lib/protocols/smtpserver.rb +556 -0
  88. data/lib/protocols/stomp.rb +130 -0
  89. data/lib/protocols/tcptest.rb +57 -0
  90. data/tasks/cpp.rake +77 -0
  91. data/tasks/project.rake +78 -0
  92. data/tasks/tests.rake +192 -0
  93. data/tests/test_attach.rb +66 -0
  94. data/tests/test_basic.rb +231 -0
  95. data/tests/test_defer.rb +47 -0
  96. data/tests/test_epoll.rb +161 -0
  97. data/tests/test_errors.rb +82 -0
  98. data/tests/test_eventables.rb +78 -0
  99. data/tests/test_exc.rb +58 -0
  100. data/tests/test_futures.rb +214 -0
  101. data/tests/test_hc.rb +218 -0
  102. data/tests/test_httpclient.rb +215 -0
  103. data/tests/test_httpclient2.rb +133 -0
  104. data/tests/test_kb.rb +61 -0
  105. data/tests/test_ltp.rb +192 -0
  106. data/tests/test_ltp2.rb +320 -0
  107. data/tests/test_next_tick.rb +102 -0
  108. data/tests/test_processes.rb +56 -0
  109. data/tests/test_pure.rb +129 -0
  110. data/tests/test_running.rb +47 -0
  111. data/tests/test_sasl.rb +74 -0
  112. data/tests/test_send_file.rb +245 -0
  113. data/tests/test_servers.rb +80 -0
  114. data/tests/test_smtpclient.rb +81 -0
  115. data/tests/test_smtpserver.rb +93 -0
  116. data/tests/test_spawn.rb +329 -0
  117. data/tests/test_ssl_args.rb +68 -0
  118. data/tests/test_timers.rb +146 -0
  119. data/tests/test_ud.rb +43 -0
  120. data/tests/testem.rb +31 -0
  121. metadata +197 -0
data/ext/ssl.h ADDED
@@ -0,0 +1,86 @@
1
+ /*****************************************************************************
2
+
3
+ $Id$
4
+
5
+ File: ssl.h
6
+ Date: 30Apr06
7
+
8
+ Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
9
+ Gmail: blackhedd
10
+
11
+ This program is free software; you can redistribute it and/or modify
12
+ it under the terms of either: 1) the GNU General Public License
13
+ as published by the Free Software Foundation; either version 2 of the
14
+ License, or (at your option) any later version; or 2) Ruby's License.
15
+
16
+ See the file COPYING for complete licensing information.
17
+
18
+ *****************************************************************************/
19
+
20
+
21
+ #ifndef __SslBox__H_
22
+ #define __SslBox__H_
23
+
24
+
25
+
26
+
27
+ #ifdef WITH_SSL
28
+
29
+ /******************
30
+ class SslContext_t
31
+ ******************/
32
+
33
+ class SslContext_t
34
+ {
35
+ public:
36
+ SslContext_t (bool is_server, const string &privkeyfile, const string &certchainfile);
37
+ virtual ~SslContext_t();
38
+
39
+ private:
40
+ static bool bLibraryInitialized;
41
+
42
+ private:
43
+ bool bIsServer;
44
+ SSL_CTX *pCtx;
45
+
46
+ EVP_PKEY *PrivateKey;
47
+ X509 *Certificate;
48
+
49
+ friend class SslBox_t;
50
+ };
51
+
52
+
53
+ /**************
54
+ class SslBox_t
55
+ **************/
56
+
57
+ class SslBox_t
58
+ {
59
+ public:
60
+ SslBox_t (bool is_server, const string &privkeyfile, const string &certchainfile);
61
+ virtual ~SslBox_t();
62
+
63
+ int PutPlaintext (const char*, int);
64
+ int GetPlaintext (char*, int);
65
+
66
+ bool PutCiphertext (const char*, int);
67
+ bool CanGetCiphertext();
68
+ int GetCiphertext (char*, int);
69
+
70
+ void Shutdown();
71
+
72
+ protected:
73
+ SslContext_t *Context;
74
+
75
+ bool bIsServer;
76
+ SSL *pSSL;
77
+ BIO *pbioRead;
78
+ BIO *pbioWrite;
79
+
80
+ PageList OutboundQ;
81
+ };
82
+ #endif // WITH_SSL
83
+
84
+
85
+ #endif // __SslBox__H_
86
+
@@ -0,0 +1,196 @@
1
+ /**
2
+ * $Id$
3
+ *
4
+ * Author:: Francis Cianfrocca (gmail: blackhedd)
5
+ * Homepage:: http://rubyeventmachine.com
6
+ * Date:: 15 Jul 2007
7
+ *
8
+ * See EventMachine and EventMachine::Connection for documentation and
9
+ * usage examples.
10
+ *
11
+ *
12
+ *----------------------------------------------------------------------------
13
+ *
14
+ * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15
+ * Gmail: blackhedd
16
+ *
17
+ * This program is free software; you can redistribute it and/or modify
18
+ * it under the terms of either: 1) the GNU General Public License
19
+ * as published by the Free Software Foundation; either version 2 of the
20
+ * License, or (at your option) any later version; or 2) Ruby's License.
21
+ *
22
+ * See the file COPYING for complete licensing information.
23
+ *
24
+ *---------------------------------------------------------------------------
25
+ *
26
+ *
27
+ */
28
+
29
+ /**
30
+ *
31
+ */
32
+ package com.rubyeventmachine;
33
+
34
+ import java.nio.ByteBuffer;
35
+ import java.nio.channels.*;
36
+ import java.util.*;
37
+ import java.io.*;
38
+ import java.net.*;
39
+ import java.net.SocketAddress;
40
+
41
+ /**
42
+ * @author francis
43
+ *
44
+ */
45
+ public class Application {
46
+
47
+
48
+ public class Reactor extends EmReactor {
49
+
50
+ private Application application;
51
+ private TreeMap<String, Timer> timers;
52
+ private TreeMap<String, Connection> connections;
53
+ private TreeMap<String, ConnectionFactory> acceptors;
54
+ /**
55
+ *
56
+ */
57
+ public Reactor (Application app) {
58
+ application = app;
59
+ timers = new TreeMap<String, Timer>();
60
+ connections = new TreeMap<String, Connection>();
61
+ acceptors = new TreeMap<String, ConnectionFactory>();
62
+ }
63
+
64
+
65
+ public void eventCallback (String sig, int eventType, ByteBuffer data) {
66
+ if (eventType == EM_TIMER_FIRED) {
67
+ String timersig = new String (data.array());
68
+ //System.out.println ("EVSIG "+sig + "..."+new String(data.array()));
69
+ Timer r = timers.remove(timersig);
70
+ if (r != null)
71
+ r._fire();
72
+ else
73
+ throw new RuntimeException ("unable to run unknown timer");
74
+ }
75
+ else if (eventType == EM_CONNECTION_COMPLETED) {
76
+ Connection c = connections.get(sig);
77
+ if (c != null) {
78
+ c.connectionCompleted();
79
+ }
80
+ else
81
+ throw new RuntimeException ("connection completed to unknown object");
82
+
83
+ }
84
+ else if (eventType == EM_CONNECTION_UNBOUND) {
85
+ Connection c = connections.get(sig);
86
+ if (c != null) {
87
+ c.unbind();
88
+ }
89
+ else
90
+ throw new RuntimeException ("unbind received on unknown object");
91
+ }
92
+ else if (eventType == EM_CONNECTION_ACCEPTED) {
93
+ ConnectionFactory f = acceptors.get(sig);
94
+ if (f != null) {
95
+ Connection c = f.connection();
96
+ c.signature = new String (data.array());
97
+ c.application = application;
98
+ connections.put(c.signature, c);
99
+ c.postInit();
100
+ //System.out.println (sig+"..."+new String(data.array()));
101
+ }
102
+ else
103
+ throw new RuntimeException ("received connection on unknown acceptor");
104
+ }
105
+ else if (eventType == EM_CONNECTION_READ) {
106
+ Connection c = connections.get(sig);
107
+ if (c != null) {
108
+ c.receiveData(data);
109
+ }
110
+ else throw new RuntimeException ("received data on unknown object");
111
+ }
112
+ else {
113
+ System.out.println ("unknown event type: " + eventType);
114
+ }
115
+ }
116
+ }
117
+
118
+
119
+ Reactor reactor;
120
+
121
+ public Application() {
122
+ reactor = new Reactor (this);
123
+ }
124
+ public void addTimer (double seconds, Timer t) {
125
+ t.application = this;
126
+ t.interval = seconds;
127
+ String s = reactor.installOneshotTimer ((int)(seconds * 1000));
128
+ reactor.timers.put(s, t);
129
+
130
+ }
131
+
132
+ public void connect (String host, int port, Connection c) {
133
+ try {
134
+ String s = reactor.connectTcpServer(host, port);
135
+ c.application = this;
136
+ c.signature = s;
137
+ reactor.connections.put(s, c);
138
+ c.postInit();
139
+ } catch (ClosedChannelException e) {}
140
+ }
141
+
142
+ public void startServer (SocketAddress sa, ConnectionFactory f) throws EmReactorException {
143
+ String s = reactor.startTcpServer(sa);
144
+ reactor.acceptors.put(s, f);
145
+ }
146
+
147
+ public void stop() {
148
+ reactor.stop();
149
+ }
150
+ public void run() {
151
+ try {
152
+ reactor.run();
153
+ } catch (IOException e) {}
154
+ }
155
+ public void run (final Runnable r) {
156
+ addTimer(0, new Timer() {
157
+ public void fire() {
158
+ r.run();
159
+ }
160
+ });
161
+ run();
162
+ }
163
+
164
+ public void sendData (String sig, ByteBuffer bb) {
165
+ try {
166
+ reactor.sendData(sig, bb);
167
+ } catch (IOException e) {}
168
+ }
169
+
170
+ public void sendDatagram (String sig, ByteBuffer bb, InetSocketAddress target) {
171
+ reactor.sendDatagram(sig, bb, target.getHostName(), target.getPort());
172
+ }
173
+
174
+ public void closeConnection (String sig, boolean afterWriting) {
175
+ try {
176
+ reactor.closeConnection(sig, afterWriting);
177
+ } catch (ClosedChannelException e) {}
178
+ }
179
+
180
+ public void openDatagramSocket (Connection c) {
181
+ openDatagramSocket (new InetSocketAddress ("0.0.0.0", 0), c);
182
+ }
183
+ public void openDatagramSocket (InetSocketAddress addr, Connection c) {
184
+ try {
185
+ String s = reactor.openUdpSocket(addr);
186
+ c.application = this;
187
+ c.signature = s;
188
+ reactor.connections.put(s, c);
189
+ c.postInit();
190
+ } catch (ClosedChannelException e) {
191
+ } catch (IOException e) {
192
+ System.out.println ("Bad Datagram socket "+e+" "+addr);
193
+ /* TODO, can't catch this here, because it can happen on a bad address */
194
+ }
195
+ }
196
+ }
@@ -0,0 +1,74 @@
1
+ /**
2
+ * $Id$
3
+ *
4
+ * Author:: Francis Cianfrocca (gmail: blackhedd)
5
+ * Homepage:: http://rubyeventmachine.com
6
+ * Date:: 15 Jul 2007
7
+ *
8
+ * See EventMachine and EventMachine::Connection for documentation and
9
+ * usage examples.
10
+ *
11
+ *
12
+ *----------------------------------------------------------------------------
13
+ *
14
+ * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15
+ * Gmail: blackhedd
16
+ *
17
+ * This program is free software; you can redistribute it and/or modify
18
+ * it under the terms of either: 1) the GNU General Public License
19
+ * as published by the Free Software Foundation; either version 2 of the
20
+ * License, or (at your option) any later version; or 2) Ruby's License.
21
+ *
22
+ * See the file COPYING for complete licensing information.
23
+ *
24
+ *---------------------------------------------------------------------------
25
+ *
26
+ *
27
+ */
28
+
29
+
30
+
31
+ package com.rubyeventmachine;
32
+
33
+ //import java.io.*;
34
+ import java.nio.*;
35
+ import java.net.*;
36
+ //import java.nio.channels.*;
37
+
38
+ public class Connection {
39
+
40
+ public Application application;
41
+ public String signature;
42
+
43
+ public void postInit() {}
44
+ public void connectionCompleted() {}
45
+ public void unbind() {}
46
+ public void receiveData (ByteBuffer bytebuffer) {}
47
+
48
+
49
+ /**
50
+ * Called by user code.
51
+ * @param bytebuffer
52
+ */
53
+ public void sendData (ByteBuffer b) {
54
+ application.sendData(signature, b);
55
+ }
56
+
57
+ /**
58
+ * This is called by user code.
59
+ * TODO: don't expose the exception here.
60
+ */
61
+ public void close() {
62
+ application.closeConnection(signature, false);
63
+ }
64
+ /**
65
+ * This is called by user code/
66
+ */
67
+ public void closeAfterWriting() {
68
+ application.closeConnection(signature, true);
69
+ }
70
+
71
+ public void sendDatagram (ByteBuffer bb, InetSocketAddress addr) {
72
+ application.sendDatagram (signature, bb, addr);
73
+ }
74
+ }
@@ -0,0 +1,37 @@
1
+ /**
2
+ * $Id$
3
+ *
4
+ * Author:: Francis Cianfrocca (gmail: blackhedd)
5
+ * Homepage:: http://rubyeventmachine.com
6
+ * Date:: 15 Jul 2007
7
+ *
8
+ * See EventMachine and EventMachine::Connection for documentation and
9
+ * usage examples.
10
+ *
11
+ *
12
+ *----------------------------------------------------------------------------
13
+ *
14
+ * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15
+ * Gmail: blackhedd
16
+ *
17
+ * This program is free software; you can redistribute it and/or modify
18
+ * it under the terms of either: 1) the GNU General Public License
19
+ * as published by the Free Software Foundation; either version 2 of the
20
+ * License, or (at your option) any later version; or 2) Ruby's License.
21
+ *
22
+ * See the file COPYING for complete licensing information.
23
+ *
24
+ *---------------------------------------------------------------------------
25
+ *
26
+ *
27
+ */
28
+
29
+
30
+
31
+ package com.rubyeventmachine;
32
+
33
+ //import com.rubyeventmachine.*;
34
+
35
+ public interface ConnectionFactory {
36
+ public Connection connection();
37
+ }
@@ -0,0 +1,46 @@
1
+ /**
2
+ * $Id$
3
+ *
4
+ * Author:: Francis Cianfrocca (gmail: blackhedd)
5
+ * Homepage:: http://rubyeventmachine.com
6
+ * Date:: 15 Jul 2007
7
+ *
8
+ * See EventMachine and EventMachine::Connection for documentation and
9
+ * usage examples.
10
+ *
11
+ *
12
+ *----------------------------------------------------------------------------
13
+ *
14
+ * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15
+ * Gmail: blackhedd
16
+ *
17
+ * This program is free software; you can redistribute it and/or modify
18
+ * it under the terms of either: 1) the GNU General Public License
19
+ * as published by the Free Software Foundation; either version 2 of the
20
+ * License, or (at your option) any later version; or 2) Ruby's License.
21
+ *
22
+ * See the file COPYING for complete licensing information.
23
+ *
24
+ *---------------------------------------------------------------------------
25
+ *
26
+ *
27
+ */
28
+
29
+
30
+
31
+ package com.rubyeventmachine;
32
+
33
+ import com.rubyeventmachine.ConnectionFactory;
34
+
35
+ public class DefaultConnectionFactory implements ConnectionFactory {
36
+
37
+ /**
38
+ * Convenience class. Its connection() method returns an instance of class
39
+ * Connection, which is usually overridden. This class is probably most
40
+ * useful for unit testing.
41
+ */
42
+ public Connection connection() {
43
+ return new Connection();
44
+ }
45
+
46
+ }
@@ -0,0 +1,408 @@
1
+ /**
2
+ * $Id$
3
+ *
4
+ * Author:: Francis Cianfrocca (gmail: blackhedd)
5
+ * Homepage:: http://rubyeventmachine.com
6
+ * Date:: 15 Jul 2007
7
+ *
8
+ * See EventMachine and EventMachine::Connection for documentation and
9
+ * usage examples.
10
+ *
11
+ *
12
+ *----------------------------------------------------------------------------
13
+ *
14
+ * Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
15
+ * Gmail: blackhedd
16
+ *
17
+ * This program is free software; you can redistribute it and/or modify
18
+ * it under the terms of either: 1) the GNU General Public License
19
+ * as published by the Free Software Foundation; either version 2 of the
20
+ * License, or (at your option) any later version; or 2) Ruby's License.
21
+ *
22
+ * See the file COPYING for complete licensing information.
23
+ *
24
+ *---------------------------------------------------------------------------
25
+ *
26
+ *
27
+ */
28
+
29
+ package com.rubyeventmachine;
30
+
31
+ import java.io.*;
32
+ import java.nio.channels.*;
33
+ import java.util.*;
34
+ import java.nio.*;
35
+ import java.net.*;
36
+ import java.util.concurrent.atomic.*;
37
+ import java.security.*;
38
+
39
+ public class EmReactor {
40
+
41
+
42
+ public final int EM_TIMER_FIRED = 100;
43
+ public final int EM_CONNECTION_READ = 101;
44
+ public final int EM_CONNECTION_UNBOUND = 102;
45
+ public final int EM_CONNECTION_ACCEPTED = 103;
46
+ public final int EM_CONNECTION_COMPLETED = 104;
47
+ public final int EM_LOOPBREAK_SIGNAL = 105;
48
+
49
+ private Selector mySelector;
50
+ private TreeMap<Long, String> Timers;
51
+ private TreeMap<String, EventableChannel> Connections;
52
+ private TreeMap<String, ServerSocketChannel> Acceptors;
53
+
54
+ private boolean bRunReactor;
55
+ private long BindingIndex;
56
+ private ByteBuffer EmptyByteBuffer;
57
+ private AtomicBoolean loopBreaker;
58
+ private ByteBuffer myReadBuffer;
59
+ private int timerQuantum;
60
+
61
+ public EmReactor() {
62
+ Timers = new TreeMap<Long, String>();
63
+ Connections = new TreeMap<String, EventableChannel>();
64
+ Acceptors = new TreeMap<String, ServerSocketChannel>();
65
+
66
+ BindingIndex = 100000;
67
+ EmptyByteBuffer = ByteBuffer.allocate(0);
68
+ loopBreaker = new AtomicBoolean();
69
+ loopBreaker.set(false);
70
+ myReadBuffer = ByteBuffer.allocate(32*1024); // don't use a direct buffer. Ruby doesn't seem to like them.
71
+ timerQuantum = 98;
72
+ }
73
+
74
+ /**
75
+ * Intended to be overridden in languages (like Ruby) that can't handle ByteBuffer. This is a stub.
76
+ * Obsolete now that I figured out how to make Ruby deal with ByteBuffers.
77
+ * @param sig
78
+ * @param eventType
79
+ * @param data
80
+ */
81
+ /*
82
+ public void stringEventCallback (String sig, int eventType, String data) {
83
+ System.out.println ("Default event callback: " + sig + " " + eventType + " " + data);
84
+ }
85
+ */
86
+
87
+ /**
88
+ * This is a no-op stub, intended to be overridden in user code.
89
+ * @param sig
90
+ * @param eventType
91
+ * @param data
92
+ */
93
+ public void eventCallback (String sig, int eventType, ByteBuffer data) {
94
+ System.out.println ("Default callback: "+sig+" "+eventType+" "+data);
95
+ //stringEventCallback (sig, eventType, new String (data.array(), data.position(), data.limit()));
96
+
97
+ }
98
+
99
+ public void run() throws IOException {
100
+ mySelector = Selector.open();
101
+ bRunReactor = true;
102
+
103
+ //int n = 0;
104
+ for (;;) {
105
+ //System.out.println ("loop "+ (n++));
106
+ if (!bRunReactor) break;
107
+ runLoopbreaks();
108
+ if (!bRunReactor) break;
109
+ runTimers();
110
+ if (!bRunReactor) break;
111
+ mySelector.select(timerQuantum);
112
+
113
+ Iterator<SelectionKey> it = mySelector.selectedKeys().iterator();
114
+ while (it.hasNext()) {
115
+ SelectionKey k = it.next();
116
+ it.remove();
117
+
118
+ try {
119
+ if (k.isAcceptable()) {
120
+ ServerSocketChannel ss = (ServerSocketChannel) k.channel();
121
+ SocketChannel sn;
122
+ while ((sn = ss.accept()) != null) {
123
+ sn.configureBlocking(false);
124
+ String b = createBinding();
125
+ EventableSocketChannel ec = new EventableSocketChannel (sn, b, mySelector);
126
+ Connections.put(b, ec);
127
+ eventCallback ((String)k.attachment(), EM_CONNECTION_ACCEPTED, ByteBuffer.wrap(b.getBytes()));
128
+ }
129
+ }
130
+
131
+ if (k.isReadable()) {
132
+ EventableChannel ec = (EventableChannel)k.attachment();
133
+ myReadBuffer.clear();
134
+ ec.readInboundData (myReadBuffer);
135
+ myReadBuffer.flip();
136
+ String b = ec.getBinding();
137
+ if (myReadBuffer.limit() > 0) {
138
+ eventCallback (b, EM_CONNECTION_READ, myReadBuffer);
139
+ }
140
+ else {
141
+ eventCallback (b, EM_CONNECTION_UNBOUND, EmptyByteBuffer);
142
+ Connections.remove(b);
143
+ k.channel().close();
144
+ }
145
+ /*
146
+ System.out.println ("READABLE");
147
+ SocketChannel sn = (SocketChannel) k.channel();
148
+ //ByteBuffer bb = ByteBuffer.allocate(16 * 1024);
149
+ // Obviously not thread-safe, since we're using the same buffer for every connection.
150
+ // This should minimize the production of garbage, though.
151
+ // TODO, we need somehow to make a call to the EventableChannel, so we can pass the
152
+ // inbound data through an SSLEngine. Hope that won't break the strategy of using one
153
+ // global read-buffer.
154
+ myReadBuffer.clear();
155
+ int r = sn.read(myReadBuffer);
156
+ if (r > 0) {
157
+ myReadBuffer.flip();
158
+ //bb = ((EventableChannel)k.attachment()).dispatchInboundData (bb);
159
+ eventCallback (((EventableChannel)k.attachment()).getBinding(), EM_CONNECTION_READ, myReadBuffer);
160
+ }
161
+ else {
162
+ // TODO. Figure out if a socket that selects readable can ever return 0 bytes
163
+ // without it being indicative of an error condition. If Java is like C, the answer is no.
164
+ String b = ((EventableChannel)k.attachment()).getBinding();
165
+ eventCallback (b, EM_CONNECTION_UNBOUND, EmptyByteBuffer);
166
+ Connections.remove(b);
167
+ sn.close();
168
+ }
169
+ */
170
+ }
171
+
172
+
173
+ if (k.isWritable()) {
174
+ EventableChannel ec = (EventableChannel)k.attachment();
175
+ if (!ec.writeOutboundData()) {
176
+ eventCallback (ec.getBinding(), EM_CONNECTION_UNBOUND, EmptyByteBuffer);
177
+ Connections.remove (ec.getBinding());
178
+ k.channel().close();
179
+ }
180
+ }
181
+
182
+ if (k.isConnectable()) {
183
+ EventableSocketChannel ec = (EventableSocketChannel)k.attachment();
184
+ if (ec.finishConnecting()) {
185
+ eventCallback (ec.getBinding(), EM_CONNECTION_COMPLETED, EmptyByteBuffer);
186
+ }
187
+ else {
188
+ Connections.remove (ec.getBinding());
189
+ k.channel().close();
190
+ eventCallback (ec.getBinding(), EM_CONNECTION_UNBOUND, EmptyByteBuffer);
191
+ }
192
+ }
193
+ }
194
+ catch (CancelledKeyException e) {
195
+ // No-op. We can come here if a read-handler closes a socket before we fall through
196
+ // to call isWritable.
197
+ }
198
+
199
+ }
200
+ }
201
+
202
+ close();
203
+ }
204
+
205
+ void close() throws IOException {
206
+ mySelector.close();
207
+ mySelector = null;
208
+
209
+ // run down open connections and sockets.
210
+ Iterator<ServerSocketChannel> i = Acceptors.values().iterator();
211
+ while (i.hasNext()) {
212
+ i.next().close();
213
+ }
214
+
215
+ Iterator<EventableChannel> i2 = Connections.values().iterator();
216
+ while (i2.hasNext())
217
+ i2.next().close();
218
+ }
219
+
220
+ void runLoopbreaks() {
221
+ if (loopBreaker.getAndSet(false)) {
222
+ eventCallback ("", EM_LOOPBREAK_SIGNAL, EmptyByteBuffer);
223
+ }
224
+ }
225
+
226
+ public void stop() {
227
+ bRunReactor = false;
228
+ signalLoopbreak();
229
+ }
230
+
231
+ void runTimers() {
232
+ long now = new Date().getTime();
233
+ while (!Timers.isEmpty()) {
234
+ long k = Timers.firstKey();
235
+ //System.out.println (k - now);
236
+ if (k > now)
237
+ break;
238
+ String s = Timers.remove(k);
239
+ eventCallback ("", EM_TIMER_FIRED, ByteBuffer.wrap(s.getBytes()));
240
+ }
241
+ }
242
+
243
+ public String installOneshotTimer (int milliseconds) {
244
+ BindingIndex++;
245
+ String s = createBinding();
246
+ Timers.put(new Date().getTime() + milliseconds, s);
247
+ return s;
248
+ }
249
+
250
+ public String startTcpServer (SocketAddress sa) throws EmReactorException {
251
+ try {
252
+ ServerSocketChannel server = ServerSocketChannel.open();
253
+ server.configureBlocking(false);
254
+ server.socket().bind (sa);
255
+ String s = createBinding();
256
+ Acceptors.put(s, server);
257
+ server.register(mySelector, SelectionKey.OP_ACCEPT, s);
258
+ return s;
259
+ } catch (IOException e) {
260
+ // TODO, should parameterize this exception better.
261
+ throw new EmReactorException ("unable to open socket acceptor");
262
+ }
263
+ }
264
+
265
+ public String startTcpServer (String address, int port) throws EmReactorException {
266
+ return startTcpServer (new InetSocketAddress (address, port));
267
+ /*
268
+ ServerSocketChannel server = ServerSocketChannel.open();
269
+ server.configureBlocking(false);
270
+ server.socket().bind(new java.net.InetSocketAddress(address, port));
271
+ String s = createBinding();
272
+ Acceptors.put(s, server);
273
+ server.register(mySelector, SelectionKey.OP_ACCEPT, s);
274
+ return s;
275
+ */
276
+ }
277
+
278
+ public void stopTcpServer (String signature) throws IOException {
279
+ ServerSocketChannel server = Acceptors.remove(signature);
280
+ if (server != null)
281
+ server.close();
282
+ else
283
+ throw new RuntimeException ("failed to close unknown acceptor");
284
+ }
285
+
286
+
287
+ public String openUdpSocket (String address, int port) throws IOException {
288
+ return openUdpSocket (new InetSocketAddress (address, port));
289
+ }
290
+ /**
291
+ *
292
+ * @param address
293
+ * @param port
294
+ * @return
295
+ * @throws IOException
296
+ */
297
+ public String openUdpSocket (InetSocketAddress address) throws IOException {
298
+ // TODO, don't throw an exception out of here.
299
+ DatagramChannel dg = DatagramChannel.open();
300
+ dg.configureBlocking(false);
301
+ dg.socket().bind(address);
302
+ String b = createBinding();
303
+ EventableChannel ec = new EventableDatagramChannel (dg, b, mySelector);
304
+ dg.register(mySelector, SelectionKey.OP_READ, ec);
305
+ Connections.put(b, ec);
306
+ return b;
307
+ }
308
+
309
+ public void sendData (String sig, ByteBuffer bb) throws IOException {
310
+ (Connections.get(sig)).scheduleOutboundData( bb );
311
+ }
312
+ public void sendData (String sig, byte[] data) throws IOException {
313
+ sendData (sig, ByteBuffer.wrap(data));
314
+ //(Connections.get(sig)).scheduleOutboundData( ByteBuffer.wrap(data.getBytes()));
315
+ }
316
+ public void setCommInactivityTimeout (String sig, long mills) {
317
+ (Connections.get(sig)).setCommInactivityTimeout (mills);
318
+ }
319
+
320
+ /**
321
+ *
322
+ * @param sig
323
+ * @param data
324
+ * @param length
325
+ * @param recipAddress
326
+ * @param recipPort
327
+ */
328
+ public void sendDatagram (String sig, String data, int length, String recipAddress, int recipPort) {
329
+ sendDatagram (sig, ByteBuffer.wrap(data.getBytes()), recipAddress, recipPort);
330
+ }
331
+
332
+ /**
333
+ *
334
+ * @param sig
335
+ * @param bb
336
+ * @param recipAddress
337
+ * @param recipPort
338
+ */
339
+ public void sendDatagram (String sig, ByteBuffer bb, String recipAddress, int recipPort) {
340
+ (Connections.get(sig)).scheduleOutboundDatagram( bb, recipAddress, recipPort);
341
+ }
342
+
343
+
344
+ /**
345
+ *
346
+ * @param address
347
+ * @param port
348
+ * @return
349
+ * @throws ClosedChannelException
350
+ */
351
+ public String connectTcpServer (String address, int port) throws ClosedChannelException {
352
+ String b = createBinding();
353
+
354
+ try {
355
+ SocketChannel sc = SocketChannel.open();
356
+ sc.configureBlocking(false);
357
+ EventableSocketChannel ec = new EventableSocketChannel (sc, b, mySelector);
358
+
359
+ if (sc.connect (new InetSocketAddress (address, port))) {
360
+ // Connection returned immediately. Can happen with localhost connections.
361
+ // WARNING, this code is untested due to lack of available test conditions.
362
+ // Ought to be be able to come here from a localhost connection, but that
363
+ // doesn't happen on Linux. (Maybe on FreeBSD?)
364
+ // The reason for not handling this until we can test it is that we
365
+ // really need to return from this function WITHOUT triggering any EM events.
366
+ // That's because until the user code has seen the signature we generated here,
367
+ // it won't be able to properly dispatch them. The C++ EM deals with this
368
+ // by setting pending mode as a flag in ALL eventable descriptors and making
369
+ // the descriptor select for writable. Then, it can send UNBOUND and
370
+ // CONNECTION_COMPLETED on the next pass through the loop, because writable will
371
+ // fire.
372
+ throw new RuntimeException ("immediate-connect unimplemented");
373
+ }
374
+ else {
375
+ Connections.put (b, ec);
376
+ ec.setConnectPending();
377
+ }
378
+ } catch (IOException e) {
379
+ // Can theoretically come here if a connect failure can be determined immediately.
380
+ // I don't know how to make that happen for testing purposes.
381
+ throw new RuntimeException ("immediate-connect unimplemented");
382
+ }
383
+ return b;
384
+ }
385
+
386
+ public void closeConnection (String sig, boolean afterWriting) throws ClosedChannelException {
387
+ Connections.get(sig).scheduleClose (afterWriting);
388
+ }
389
+
390
+ String createBinding() {
391
+ return new String ("BND_" + (++BindingIndex));
392
+ }
393
+
394
+ public void signalLoopbreak() {
395
+ loopBreaker.set(true);
396
+ mySelector.wakeup();
397
+ }
398
+
399
+ public void startTls (String sig) throws NoSuchAlgorithmException, KeyManagementException {
400
+ Connections.get(sig).startTls();
401
+ }
402
+
403
+ public void setTimerQuantum (int mills) {
404
+ if (mills < 5 || mills > 2500)
405
+ throw new RuntimeException ("attempt to set invalid timer-quantum value: "+mills);
406
+ timerQuantum = mills;
407
+ }
408
+ }