wj_eventmachine 1.3.0.dev.1

Sign up to get free protection for your applications and to get access to all the features.
Files changed (180) hide show
  1. checksums.yaml +7 -0
  2. data/CHANGELOG.md +179 -0
  3. data/GNU +281 -0
  4. data/LICENSE +60 -0
  5. data/README.md +110 -0
  6. data/docs/DocumentationGuidesIndex.md +27 -0
  7. data/docs/GettingStarted.md +520 -0
  8. data/docs/old/ChangeLog +211 -0
  9. data/docs/old/DEFERRABLES +246 -0
  10. data/docs/old/EPOLL +141 -0
  11. data/docs/old/INSTALL +13 -0
  12. data/docs/old/KEYBOARD +42 -0
  13. data/docs/old/LEGAL +25 -0
  14. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  15. data/docs/old/PURE_RUBY +75 -0
  16. data/docs/old/RELEASE_NOTES +94 -0
  17. data/docs/old/SMTP +4 -0
  18. data/docs/old/SPAWNED_PROCESSES +148 -0
  19. data/docs/old/TODO +8 -0
  20. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  21. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  22. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  23. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  24. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  25. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  26. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  27. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  28. data/examples/old/ex_channel.rb +43 -0
  29. data/examples/old/ex_queue.rb +2 -0
  30. data/examples/old/ex_tick_loop_array.rb +15 -0
  31. data/examples/old/ex_tick_loop_counter.rb +32 -0
  32. data/examples/old/helper.rb +2 -0
  33. data/ext/binder.cpp +124 -0
  34. data/ext/binder.h +52 -0
  35. data/ext/cmain.cpp +1046 -0
  36. data/ext/ed.cpp +2238 -0
  37. data/ext/ed.h +460 -0
  38. data/ext/em.cpp +2378 -0
  39. data/ext/em.h +266 -0
  40. data/ext/eventmachine.h +152 -0
  41. data/ext/extconf.rb +285 -0
  42. data/ext/fastfilereader/extconf.rb +120 -0
  43. data/ext/fastfilereader/mapper.cpp +214 -0
  44. data/ext/fastfilereader/mapper.h +59 -0
  45. data/ext/fastfilereader/rubymain.cpp +126 -0
  46. data/ext/kb.cpp +79 -0
  47. data/ext/page.cpp +107 -0
  48. data/ext/page.h +51 -0
  49. data/ext/pipe.cpp +354 -0
  50. data/ext/project.h +174 -0
  51. data/ext/rubymain.cpp +1610 -0
  52. data/ext/ssl.cpp +627 -0
  53. data/ext/ssl.h +103 -0
  54. data/ext/wait_for_single_fd.h +36 -0
  55. data/java/.classpath +8 -0
  56. data/java/.project +17 -0
  57. data/java/src/com/rubyeventmachine/EmReactor.java +625 -0
  58. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  59. data/java/src/com/rubyeventmachine/EmReactorInterface.java +70 -0
  60. data/java/src/com/rubyeventmachine/EventableChannel.java +72 -0
  61. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +201 -0
  62. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +415 -0
  63. data/java/src/com/rubyeventmachine/NullEmReactor.java +157 -0
  64. data/java/src/com/rubyeventmachine/NullEventableChannel.java +81 -0
  65. data/lib/em/buftok.rb +59 -0
  66. data/lib/em/callback.rb +58 -0
  67. data/lib/em/channel.rb +69 -0
  68. data/lib/em/completion.rb +307 -0
  69. data/lib/em/connection.rb +776 -0
  70. data/lib/em/deferrable.rb +210 -0
  71. data/lib/em/deferrable/pool.rb +2 -0
  72. data/lib/em/file_watch.rb +73 -0
  73. data/lib/em/future.rb +61 -0
  74. data/lib/em/io_streamer.rb +68 -0
  75. data/lib/em/iterator.rb +252 -0
  76. data/lib/em/messages.rb +66 -0
  77. data/lib/em/pool.rb +151 -0
  78. data/lib/em/process_watch.rb +45 -0
  79. data/lib/em/processes.rb +123 -0
  80. data/lib/em/protocols.rb +37 -0
  81. data/lib/em/protocols/header_and_content.rb +138 -0
  82. data/lib/em/protocols/httpclient.rb +303 -0
  83. data/lib/em/protocols/httpclient2.rb +602 -0
  84. data/lib/em/protocols/line_and_text.rb +125 -0
  85. data/lib/em/protocols/line_protocol.rb +33 -0
  86. data/lib/em/protocols/linetext2.rb +179 -0
  87. data/lib/em/protocols/memcache.rb +331 -0
  88. data/lib/em/protocols/object_protocol.rb +46 -0
  89. data/lib/em/protocols/postgres3.rb +246 -0
  90. data/lib/em/protocols/saslauth.rb +175 -0
  91. data/lib/em/protocols/smtpclient.rb +394 -0
  92. data/lib/em/protocols/smtpserver.rb +666 -0
  93. data/lib/em/protocols/socks4.rb +66 -0
  94. data/lib/em/protocols/stomp.rb +205 -0
  95. data/lib/em/protocols/tcptest.rb +54 -0
  96. data/lib/em/pure_ruby.rb +1299 -0
  97. data/lib/em/queue.rb +80 -0
  98. data/lib/em/resolver.rb +232 -0
  99. data/lib/em/spawnable.rb +84 -0
  100. data/lib/em/streamer.rb +118 -0
  101. data/lib/em/threaded_resource.rb +90 -0
  102. data/lib/em/tick_loop.rb +85 -0
  103. data/lib/em/timers.rb +61 -0
  104. data/lib/em/version.rb +3 -0
  105. data/lib/eventmachine.rb +1602 -0
  106. data/lib/jeventmachine.rb +318 -0
  107. data/rakelib/package.rake +120 -0
  108. data/rakelib/test.rake +6 -0
  109. data/rakelib/test_pure.rake +11 -0
  110. data/tests/client.crt +31 -0
  111. data/tests/client.key +51 -0
  112. data/tests/dhparam.pem +13 -0
  113. data/tests/em_ssl_handlers.rb +153 -0
  114. data/tests/em_test_helper.rb +198 -0
  115. data/tests/jruby/test_jeventmachine.rb +38 -0
  116. data/tests/test_attach.rb +199 -0
  117. data/tests/test_basic.rb +321 -0
  118. data/tests/test_channel.rb +75 -0
  119. data/tests/test_completion.rb +178 -0
  120. data/tests/test_connection_count.rb +83 -0
  121. data/tests/test_connection_write.rb +35 -0
  122. data/tests/test_defer.rb +35 -0
  123. data/tests/test_deferrable.rb +35 -0
  124. data/tests/test_epoll.rb +141 -0
  125. data/tests/test_error_handler.rb +38 -0
  126. data/tests/test_exc.rb +37 -0
  127. data/tests/test_file_watch.rb +86 -0
  128. data/tests/test_fork.rb +75 -0
  129. data/tests/test_futures.rb +170 -0
  130. data/tests/test_handler_check.rb +35 -0
  131. data/tests/test_hc.rb +155 -0
  132. data/tests/test_httpclient.rb +238 -0
  133. data/tests/test_httpclient2.rb +132 -0
  134. data/tests/test_idle_connection.rb +31 -0
  135. data/tests/test_inactivity_timeout.rb +102 -0
  136. data/tests/test_io_streamer.rb +47 -0
  137. data/tests/test_ipv4.rb +96 -0
  138. data/tests/test_ipv6.rb +107 -0
  139. data/tests/test_iterator.rb +122 -0
  140. data/tests/test_kb.rb +28 -0
  141. data/tests/test_keepalive.rb +113 -0
  142. data/tests/test_line_protocol.rb +33 -0
  143. data/tests/test_ltp.rb +155 -0
  144. data/tests/test_ltp2.rb +332 -0
  145. data/tests/test_many_fds.rb +21 -0
  146. data/tests/test_next_tick.rb +104 -0
  147. data/tests/test_object_protocol.rb +36 -0
  148. data/tests/test_pause.rb +109 -0
  149. data/tests/test_pending_connect_timeout.rb +52 -0
  150. data/tests/test_pool.rb +196 -0
  151. data/tests/test_process_watch.rb +50 -0
  152. data/tests/test_processes.rb +128 -0
  153. data/tests/test_proxy_connection.rb +180 -0
  154. data/tests/test_pure.rb +156 -0
  155. data/tests/test_queue.rb +64 -0
  156. data/tests/test_resolver.rb +129 -0
  157. data/tests/test_running.rb +14 -0
  158. data/tests/test_sasl.rb +46 -0
  159. data/tests/test_send_file.rb +217 -0
  160. data/tests/test_servers.rb +32 -0
  161. data/tests/test_shutdown_hooks.rb +23 -0
  162. data/tests/test_smtpclient.rb +75 -0
  163. data/tests/test_smtpserver.rb +90 -0
  164. data/tests/test_sock_opt.rb +53 -0
  165. data/tests/test_spawn.rb +290 -0
  166. data/tests/test_ssl_args.rb +41 -0
  167. data/tests/test_ssl_dhparam.rb +57 -0
  168. data/tests/test_ssl_ecdh_curve.rb +57 -0
  169. data/tests/test_ssl_extensions.rb +24 -0
  170. data/tests/test_ssl_methods.rb +31 -0
  171. data/tests/test_ssl_protocols.rb +190 -0
  172. data/tests/test_ssl_verify.rb +52 -0
  173. data/tests/test_stomp.rb +38 -0
  174. data/tests/test_system.rb +46 -0
  175. data/tests/test_threaded_resource.rb +68 -0
  176. data/tests/test_tick_loop.rb +58 -0
  177. data/tests/test_timers.rb +150 -0
  178. data/tests/test_ud.rb +8 -0
  179. data/tests/test_unbind_reason.rb +40 -0
  180. metadata +384 -0
@@ -0,0 +1,103 @@
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 std::string &privkeyfile, const std::string &certchainfile, const std::string &cipherlist, const std::string &ecdh_curve, const std::string &dhparam, int ssl_version);
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
+ #define SSLBOX_INPUT_CHUNKSIZE 2019
58
+ #define SSLBOX_OUTPUT_CHUNKSIZE 2048
59
+ #define SSLBOX_WRITE_BUFFER_SIZE 8192 // (SSLBOX_OUTPUT_CHUNKSIZE * 4)
60
+
61
+ class SslBox_t
62
+ {
63
+ public:
64
+ SslBox_t (bool is_server, const std::string &privkeyfile, const std::string &certchainfile, bool verify_peer, bool fail_if_no_peer_cert, const std::string &snihostname, const std::string &cipherlist, const std::string &ecdh_curve, const std::string &dhparam, int ssl_version, const uintptr_t binding);
65
+ virtual ~SslBox_t();
66
+
67
+ int PutPlaintext (const char*, int);
68
+ int GetPlaintext (char*, int);
69
+
70
+ bool PutCiphertext (const char*, int);
71
+ bool CanGetCiphertext();
72
+ int GetCiphertext (char*, int);
73
+ bool IsHandshakeCompleted() {return bHandshakeCompleted;}
74
+
75
+ X509 *GetPeerCert();
76
+ int GetCipherBits();
77
+ const char *GetCipherName();
78
+ const char *GetCipherProtocol();
79
+ const char *GetSNIHostname();
80
+
81
+ void Shutdown();
82
+
83
+ protected:
84
+ SslContext_t *Context;
85
+
86
+ bool bIsServer;
87
+ bool bHandshakeCompleted;
88
+ bool bVerifyPeer;
89
+ bool bFailIfNoPeerCert;
90
+ SSL *pSSL;
91
+ BIO *pbioRead;
92
+ BIO *pbioWrite;
93
+
94
+ PageList OutboundQ;
95
+ };
96
+
97
+ extern "C" int ssl_verify_wrapper(int, X509_STORE_CTX*);
98
+
99
+ #endif // WITH_SSL
100
+
101
+
102
+ #endif // __SslBox__H_
103
+
@@ -0,0 +1,36 @@
1
+ /*
2
+ * backwards compatibility for pre-1.9.3 C API
3
+ *
4
+ * Ruby 1.9.3 provides this API which allows the use of ppoll() on Linux
5
+ * to minimize select() and malloc() overhead on high-numbered FDs.
6
+ */
7
+ #ifdef HAVE_RB_WAIT_FOR_SINGLE_FD
8
+ # include <ruby/io.h>
9
+ #else
10
+ # define RB_WAITFD_IN 0x001
11
+ # define RB_WAITFD_PRI 0x002
12
+ # define RB_WAITFD_OUT 0x004
13
+
14
+ static int my_wait_for_single_fd(int fd, int events, struct timeval *tvp)
15
+ {
16
+ fd_set fdset;
17
+ fd_set *rfds = NULL;
18
+ fd_set *wfds = NULL;
19
+ fd_set *efds = NULL;
20
+
21
+ FD_ZERO(&fdset);
22
+ FD_SET(fd, &fdset);
23
+
24
+ if (events & RB_WAITFD_IN)
25
+ rfds = &fdset;
26
+ if (events & RB_WAITFD_OUT)
27
+ wfds = &fdset;
28
+ if (events & RB_WAITFD_PRI)
29
+ efds = &fdset;
30
+
31
+ return rb_thread_select(fd + 1, rfds, wfds, efds, tvp);
32
+ }
33
+
34
+ #define rb_wait_for_single_fd(fd,events,tvp) \
35
+ my_wait_for_single_fd((fd),(events),(tvp))
36
+ #endif
@@ -0,0 +1,8 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <classpath>
3
+ <classpathentry kind="src" path="src"/>
4
+ <classpathentry excluding="src/" kind="src" path=""/>
5
+ <classpathentry kind="con" path="org.eclipse.jdt.launching.JRE_CONTAINER"/>
6
+ <classpathentry kind="con" path="org.eclipse.jdt.junit.JUNIT_CONTAINER/4"/>
7
+ <classpathentry kind="output" path="src"/>
8
+ </classpath>
@@ -0,0 +1,17 @@
1
+ <?xml version="1.0" encoding="UTF-8"?>
2
+ <projectDescription>
3
+ <name>em_reactor</name>
4
+ <comment></comment>
5
+ <projects>
6
+ </projects>
7
+ <buildSpec>
8
+ <buildCommand>
9
+ <name>org.eclipse.jdt.core.javabuilder</name>
10
+ <arguments>
11
+ </arguments>
12
+ </buildCommand>
13
+ </buildSpec>
14
+ <natures>
15
+ <nature>org.eclipse.jdt.core.javanature</nature>
16
+ </natures>
17
+ </projectDescription>
@@ -0,0 +1,625 @@
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 implements EmReactorInterface
40
+ {
41
+ private static final NullEventableChannel NULL_EVENTABLE_CHANNEL = new NullEventableChannel();
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
+ public final int EM_CONNECTION_NOTIFY_READABLE = 106;
49
+ public final int EM_CONNECTION_NOTIFY_WRITABLE = 107;
50
+ public final int EM_SSL_HANDSHAKE_COMPLETED = 108;
51
+ public final int EM_SSL_VERIFY = 109;
52
+ public final int EM_PROXY_TARGET_UNBOUND = 110;
53
+ public final int EM_PROXY_COMPLETED = 111;
54
+
55
+ public final int EM_PROTO_SSLv2 = 2;
56
+ public final int EM_PROTO_SSLv3 = 4;
57
+ public final int EM_PROTO_TLSv1 = 8;
58
+ public final int EM_PROTO_TLSv1_1 = 16;
59
+ public final int EM_PROTO_TLSv1_2 = 32;
60
+
61
+ private Selector mySelector;
62
+ private TreeMap<Long, ArrayList<Long>> Timers;
63
+ private HashMap<Long, EventableChannel> Connections;
64
+ private HashMap<Long, ServerSocketChannel> Acceptors;
65
+ private ArrayList<Long> NewConnections;
66
+ private ArrayList<Long> UnboundConnections;
67
+ private ArrayList<EventableSocketChannel> DetachedConnections;
68
+
69
+ private boolean bRunReactor;
70
+ private long BindingIndex;
71
+ private AtomicBoolean loopBreaker;
72
+ private ByteBuffer myReadBuffer;
73
+ private int timerQuantum;
74
+
75
+ public EmReactor() {
76
+ Timers = new TreeMap<Long, ArrayList<Long>>();
77
+ Connections = new HashMap<Long, EventableChannel>();
78
+ Acceptors = new HashMap<Long, ServerSocketChannel>();
79
+ NewConnections = new ArrayList<Long>();
80
+ UnboundConnections = new ArrayList<Long>();
81
+ DetachedConnections = new ArrayList<EventableSocketChannel>();
82
+
83
+ BindingIndex = 0;
84
+ loopBreaker = new AtomicBoolean();
85
+ loopBreaker.set(false);
86
+ myReadBuffer = ByteBuffer.allocate(32*1024); // don't use a direct buffer. Ruby doesn't seem to like them.
87
+ timerQuantum = 98;
88
+ }
89
+
90
+ /**
91
+ * This is a no-op stub, intended to be overridden in user code.
92
+ */
93
+ public void eventCallback (long sig, int eventType, ByteBuffer data, long data2) {
94
+ System.out.println ("Default callback: "+sig+" "+eventType+" "+data+" "+data2);
95
+ }
96
+ public void eventCallback (long sig, int eventType, ByteBuffer data) {
97
+ eventCallback (sig, eventType, data, 0);
98
+ }
99
+
100
+
101
+ public void run() {
102
+ try {
103
+ mySelector = Selector.open();
104
+ bRunReactor = true;
105
+ } catch (IOException e) {
106
+ throw new RuntimeException ("Could not open selector", e);
107
+ }
108
+
109
+ while (bRunReactor) {
110
+ runLoopbreaks();
111
+ if (!bRunReactor) break;
112
+
113
+ runTimers();
114
+ if (!bRunReactor) break;
115
+
116
+ removeUnboundConnections();
117
+ checkIO();
118
+ addNewConnections();
119
+ processIO();
120
+ }
121
+
122
+ close();
123
+ }
124
+
125
+ void addNewConnections() {
126
+ ListIterator<EventableSocketChannel> iter = DetachedConnections.listIterator(0);
127
+ while (iter.hasNext()) {
128
+ EventableSocketChannel ec = iter.next();
129
+ ec.cleanup();
130
+ }
131
+ DetachedConnections.clear();
132
+
133
+ ListIterator<Long> iter2 = NewConnections.listIterator(0);
134
+ while (iter2.hasNext()) {
135
+ long b = iter2.next();
136
+
137
+ EventableChannel ec = getConnection(b);
138
+ if (ec != null) {
139
+ try {
140
+ ec.register();
141
+ } catch (ClosedChannelException e) {
142
+ UnboundConnections.add (ec.getBinding());
143
+ }
144
+ }
145
+ }
146
+ NewConnections.clear();
147
+ }
148
+
149
+ void removeUnboundConnections() {
150
+ ListIterator<Long> iter = UnboundConnections.listIterator(0);
151
+ while (iter.hasNext()) {
152
+ long b = iter.next();
153
+
154
+ EventableChannel ec = Connections.remove(b);
155
+ if (ec != null) {
156
+ eventCallback (b, EM_CONNECTION_UNBOUND, null);
157
+ ec.close();
158
+
159
+ EventableSocketChannel sc = (EventableSocketChannel) ec;
160
+ if (sc != null && sc.isAttached())
161
+ DetachedConnections.add (sc);
162
+ }
163
+ }
164
+ UnboundConnections.clear();
165
+ }
166
+
167
+ void checkIO() {
168
+ long timeout;
169
+
170
+ if (NewConnections.size() > 0) {
171
+ timeout = -1;
172
+ } else if (!Timers.isEmpty()) {
173
+ long now = new Date().getTime();
174
+ long k = Timers.firstKey();
175
+ long diff = k-now;
176
+
177
+ if (diff <= 0)
178
+ timeout = -1; // don't wait, just poll once
179
+ else
180
+ timeout = diff;
181
+ } else {
182
+ timeout = 0; // wait indefinitely
183
+ }
184
+
185
+ try {
186
+ if (timeout == -1)
187
+ mySelector.selectNow();
188
+ else
189
+ mySelector.select(timeout);
190
+ } catch (IOException e) {
191
+ e.printStackTrace();
192
+ }
193
+ }
194
+
195
+ void processIO() {
196
+ Iterator<SelectionKey> it = mySelector.selectedKeys().iterator();
197
+ while (it.hasNext()) {
198
+ SelectionKey k = it.next();
199
+ it.remove();
200
+
201
+ if (k.isConnectable())
202
+ isConnectable(k);
203
+
204
+ else if (k.isAcceptable())
205
+ isAcceptable(k);
206
+
207
+ else {
208
+ if (k.isWritable())
209
+ isWritable(k);
210
+
211
+ if (k.isReadable())
212
+ isReadable(k);
213
+ }
214
+ }
215
+ }
216
+
217
+ void isAcceptable (SelectionKey k) {
218
+ ServerSocketChannel ss = (ServerSocketChannel) k.channel();
219
+ SocketChannel sn;
220
+ long b;
221
+
222
+ for (int n = 0; n < 10; n++) {
223
+ try {
224
+ sn = ss.accept();
225
+ if (sn == null)
226
+ break;
227
+ } catch (IOException e) {
228
+ e.printStackTrace();
229
+ k.cancel();
230
+
231
+ ServerSocketChannel server = Acceptors.remove(k.attachment());
232
+ if (server != null)
233
+ try{ server.close(); } catch (IOException ex) {};
234
+ break;
235
+ }
236
+
237
+ try {
238
+ sn.configureBlocking(false);
239
+ } catch (IOException e) {
240
+ e.printStackTrace();
241
+ continue;
242
+ }
243
+
244
+ b = createBinding();
245
+ EventableSocketChannel ec = new EventableSocketChannel (sn, b, mySelector);
246
+ Connections.put (b, ec);
247
+ NewConnections.add (b);
248
+
249
+ eventCallback (((Long)k.attachment()).longValue(), EM_CONNECTION_ACCEPTED, null, b);
250
+ }
251
+ }
252
+
253
+ void isReadable (SelectionKey k) {
254
+ EventableChannel ec = (EventableChannel) k.attachment();
255
+ long b = ec.getBinding();
256
+
257
+ if (ec.isWatchOnly()) {
258
+ if (ec.isNotifyReadable())
259
+ eventCallback (b, EM_CONNECTION_NOTIFY_READABLE, null);
260
+ } else {
261
+ myReadBuffer.clear();
262
+
263
+ try {
264
+ ec.readInboundData (myReadBuffer);
265
+ myReadBuffer.flip();
266
+ if (myReadBuffer.limit() > 0)
267
+ eventCallback (b, EM_CONNECTION_READ, myReadBuffer);
268
+ } catch (IOException e) {
269
+ UnboundConnections.add (b);
270
+ }
271
+ }
272
+ }
273
+
274
+ void isWritable (SelectionKey k) {
275
+ EventableChannel ec = (EventableChannel) k.attachment();
276
+ long b = ec.getBinding();
277
+
278
+ if (ec.isWatchOnly()) {
279
+ if (ec.isNotifyWritable())
280
+ eventCallback (b, EM_CONNECTION_NOTIFY_WRITABLE, null);
281
+ }
282
+ else {
283
+ try {
284
+ if (!ec.writeOutboundData())
285
+ UnboundConnections.add (b);
286
+ } catch (IOException e) {
287
+ UnboundConnections.add (b);
288
+ }
289
+ }
290
+ }
291
+
292
+ void isConnectable (SelectionKey k) {
293
+ EventableSocketChannel ec = (EventableSocketChannel) k.attachment();
294
+ long b = ec.getBinding();
295
+
296
+ try {
297
+ if (ec.finishConnecting())
298
+ eventCallback (b, EM_CONNECTION_COMPLETED, null);
299
+ else
300
+ UnboundConnections.add (b);
301
+ } catch (IOException e) {
302
+ UnboundConnections.add (b);
303
+ }
304
+ }
305
+
306
+ void close() {
307
+ try {
308
+ if (mySelector != null)
309
+ mySelector.close();
310
+ } catch (IOException e) {}
311
+ mySelector = null;
312
+
313
+ // run down open connections and sockets.
314
+ Iterator<ServerSocketChannel> i = Acceptors.values().iterator();
315
+ while (i.hasNext()) {
316
+ try {
317
+ i.next().close();
318
+ } catch (IOException e) {}
319
+ }
320
+
321
+ // 29Sep09: We create an ArrayList of the existing connections, then iterate over
322
+ // that to call unbind on them. This is because an unbind can trigger a reconnect,
323
+ // which will add to the Connections HashMap, causing a ConcurrentModificationException.
324
+ // XXX: The correct behavior here would be to latch the various reactor methods to return
325
+ // immediately if the reactor is shutting down.
326
+ ArrayList<EventableChannel> conns = new ArrayList<EventableChannel>();
327
+ Iterator<EventableChannel> i2 = Connections.values().iterator();
328
+ while (i2.hasNext()) {
329
+ EventableChannel ec = i2.next();
330
+ if (ec != null) {
331
+ conns.add (ec);
332
+ }
333
+ }
334
+ Connections.clear();
335
+
336
+ ListIterator<EventableChannel> i3 = conns.listIterator(0);
337
+ while (i3.hasNext()) {
338
+ EventableChannel ec = i3.next();
339
+ eventCallback (ec.getBinding(), EM_CONNECTION_UNBOUND, null);
340
+ ec.close();
341
+
342
+ EventableSocketChannel sc = (EventableSocketChannel) ec;
343
+ if (sc != null && sc.isAttached())
344
+ DetachedConnections.add (sc);
345
+ }
346
+
347
+ ListIterator<EventableSocketChannel> i4 = DetachedConnections.listIterator(0);
348
+ while (i4.hasNext()) {
349
+ EventableSocketChannel ec = i4.next();
350
+ ec.cleanup();
351
+ }
352
+ DetachedConnections.clear();
353
+ }
354
+
355
+ void runLoopbreaks() {
356
+ if (loopBreaker.getAndSet(false)) {
357
+ eventCallback (0, EM_LOOPBREAK_SIGNAL, null);
358
+ }
359
+ }
360
+
361
+ public void stop() {
362
+ bRunReactor = false;
363
+ signalLoopbreak();
364
+ }
365
+
366
+ void runTimers() {
367
+ long now = new Date().getTime();
368
+ while (!Timers.isEmpty()) {
369
+ long k = Timers.firstKey();
370
+ if (k > now)
371
+ break;
372
+
373
+ ArrayList<Long> callbacks = Timers.get(k);
374
+ Timers.remove(k);
375
+
376
+ // Fire all timers at this timestamp
377
+ ListIterator<Long> iter = callbacks.listIterator(0);
378
+ while (iter.hasNext()) {
379
+ eventCallback (0, EM_TIMER_FIRED, null, iter.next().longValue());
380
+ }
381
+ }
382
+ }
383
+
384
+ public long installOneshotTimer (long milliseconds) {
385
+ long s = createBinding();
386
+ long deadline = new Date().getTime() + milliseconds;
387
+
388
+ if (Timers.containsKey(deadline)) {
389
+ Timers.get(deadline).add(s);
390
+ } else {
391
+ ArrayList<Long> callbacks = new ArrayList<Long>();
392
+ callbacks.add(s);
393
+ Timers.put(deadline, callbacks);
394
+ }
395
+
396
+ return s;
397
+ }
398
+
399
+ public long startTcpServer (SocketAddress sa) throws EmReactorException {
400
+ try {
401
+ ServerSocketChannel server = ServerSocketChannel.open();
402
+ server.configureBlocking(false);
403
+ server.socket().bind (sa);
404
+ long s = createBinding();
405
+ Acceptors.put(s, server);
406
+ server.register(mySelector, SelectionKey.OP_ACCEPT, s);
407
+ return s;
408
+ } catch (IOException e) {
409
+ throw new EmReactorException ("unable to open socket acceptor: " + e.toString());
410
+ }
411
+ }
412
+
413
+ public long startTcpServer (String address, int port) throws EmReactorException {
414
+ return startTcpServer (new InetSocketAddress (address, port));
415
+ }
416
+
417
+ public void stopTcpServer (long signature) throws IOException {
418
+ ServerSocketChannel server = Acceptors.remove(signature);
419
+ if (server != null)
420
+ server.close();
421
+ else
422
+ throw new RuntimeException ("failed to close unknown acceptor");
423
+ }
424
+
425
+ public long openUdpSocket (InetSocketAddress address) throws IOException {
426
+ // TODO, don't throw an exception out of here.
427
+ DatagramChannel dg = DatagramChannel.open();
428
+ dg.configureBlocking(false);
429
+ dg.socket().bind(address);
430
+ long b = createBinding();
431
+ EventableChannel ec = new EventableDatagramChannel (dg, b, mySelector);
432
+ dg.register(mySelector, SelectionKey.OP_READ, ec);
433
+ Connections.put(b, ec);
434
+ return b;
435
+ }
436
+
437
+ public long openUdpSocket (String address, int port) throws IOException {
438
+ return openUdpSocket (new InetSocketAddress (address, port));
439
+ }
440
+
441
+ public void sendData (long sig, ByteBuffer bb) throws IOException {
442
+ getConnection(sig).scheduleOutboundData(bb);
443
+ }
444
+
445
+ private EventableChannel getConnection(long sig)
446
+ {
447
+ EventableChannel channel = Connections.get(sig);
448
+ if (channel == null)
449
+ {
450
+ channel = NULL_EVENTABLE_CHANNEL;
451
+ }
452
+ return channel;
453
+ }
454
+
455
+ public void sendData (long sig, byte[] data) throws IOException {
456
+ sendData (sig, ByteBuffer.wrap(data));
457
+ }
458
+
459
+ public void setCommInactivityTimeout (long sig, long mills) {
460
+ getConnection(sig).setCommInactivityTimeout(mills);
461
+ }
462
+
463
+ public void sendDatagram (long sig, byte[] data, int length, String recipAddress, int recipPort) {
464
+ sendDatagram (sig, ByteBuffer.wrap(data), recipAddress, recipPort);
465
+ }
466
+
467
+ public void sendDatagram (long sig, ByteBuffer bb, String recipAddress, int recipPort) {
468
+ (getConnection(sig)).scheduleOutboundDatagram( bb, recipAddress, recipPort);
469
+ }
470
+
471
+ public long connectTcpServer (String address, int port) {
472
+ return connectTcpServer(null, 0, address, port);
473
+ }
474
+
475
+ public long connectTcpServer (String bindAddr, int bindPort, String address, int port) {
476
+ long b = createBinding();
477
+
478
+ try {
479
+ SocketChannel sc = SocketChannel.open();
480
+ sc.configureBlocking(false);
481
+ if (bindAddr != null)
482
+ sc.socket().bind(new InetSocketAddress (bindAddr, bindPort));
483
+
484
+ EventableSocketChannel ec = new EventableSocketChannel (sc, b, mySelector);
485
+
486
+ if (sc.connect (new InetSocketAddress (address, port))) {
487
+ // Connection returned immediately. Can happen with localhost connections.
488
+ // WARNING, this code is untested due to lack of available test conditions.
489
+ // Ought to be be able to come here from a localhost connection, but that
490
+ // doesn't happen on Linux. (Maybe on FreeBSD?)
491
+ // The reason for not handling this until we can test it is that we
492
+ // really need to return from this function WITHOUT triggering any EM events.
493
+ // That's because until the user code has seen the signature we generated here,
494
+ // it won't be able to properly dispatch them. The C++ EM deals with this
495
+ // by setting pending mode as a flag in ALL eventable descriptors and making
496
+ // the descriptor select for writable. Then, it can send UNBOUND and
497
+ // CONNECTION_COMPLETED on the next pass through the loop, because writable will
498
+ // fire.
499
+ throw new RuntimeException ("immediate-connect unimplemented");
500
+ }
501
+ else {
502
+ ec.setConnectPending();
503
+ Connections.put (b, ec);
504
+ NewConnections.add (b);
505
+ }
506
+ } catch (IOException e) {
507
+ // Can theoretically come here if a connect failure can be determined immediately.
508
+ // I don't know how to make that happen for testing purposes.
509
+ throw new RuntimeException ("immediate-connect unimplemented: " + e.toString());
510
+ }
511
+ return b;
512
+ }
513
+
514
+ public void closeConnection (long sig, boolean afterWriting) {
515
+ EventableChannel ec = getConnection(sig);
516
+ if (ec != null)
517
+ if (ec.scheduleClose (afterWriting))
518
+ UnboundConnections.add (sig);
519
+ }
520
+
521
+ long createBinding() {
522
+ return ++BindingIndex;
523
+ }
524
+
525
+ public void signalLoopbreak() {
526
+ loopBreaker.set(true);
527
+ if (mySelector != null)
528
+ mySelector.wakeup();
529
+ }
530
+
531
+ public void startTls (long sig) throws NoSuchAlgorithmException, KeyManagementException {
532
+ getConnection(sig).startTls();
533
+ }
534
+
535
+ public void setTimerQuantum (int mills) {
536
+ if (mills < 5 || mills > 2500)
537
+ throw new RuntimeException ("attempt to set invalid timer-quantum value: "+mills);
538
+ timerQuantum = mills;
539
+ }
540
+
541
+ public Object[] getPeerName (long sig) {
542
+ EventableChannel channel = Connections.get(sig);
543
+ if (channel != null) {
544
+ return Connections.get(sig).getPeerName();
545
+ }
546
+ else {
547
+ ServerSocketChannel acceptor = Acceptors.get(sig);
548
+ return new Object[] { acceptor.socket().getLocalPort(),
549
+ acceptor.socket().getInetAddress().getHostAddress() };
550
+ }
551
+ }
552
+
553
+ public Object[] getSockName (long sig) {
554
+ EventableChannel channel = Connections.get(sig);
555
+ if (channel != null) {
556
+ return Connections.get(sig).getSockName();
557
+ }
558
+ else {
559
+ ServerSocketChannel acceptor = Acceptors.get(sig);
560
+ return new Object[] { acceptor.socket().getLocalPort(),
561
+ acceptor.socket().getInetAddress().getHostAddress() };
562
+ }
563
+ }
564
+
565
+ public long attachChannel (SocketChannel sc, boolean watch_mode) {
566
+ long b = createBinding();
567
+
568
+ EventableSocketChannel ec = new EventableSocketChannel (sc, b, mySelector);
569
+
570
+ ec.setAttached();
571
+ if (watch_mode)
572
+ ec.setWatchOnly();
573
+
574
+ Connections.put (b, ec);
575
+ NewConnections.add (b);
576
+
577
+ return b;
578
+ }
579
+
580
+ public SocketChannel detachChannel (long sig) {
581
+ EventableSocketChannel ec = (EventableSocketChannel) getConnection(sig);
582
+ if (ec != null) {
583
+ UnboundConnections.add (sig);
584
+ return ec.getChannel();
585
+ } else {
586
+ return null;
587
+ }
588
+ }
589
+
590
+ public void setNotifyReadable (long sig, boolean mode) {
591
+ ((EventableSocketChannel) getConnection(sig)).setNotifyReadable(mode);
592
+ }
593
+
594
+ public void setNotifyWritable (long sig, boolean mode) {
595
+ ((EventableSocketChannel) getConnection(sig)).setNotifyWritable(mode);
596
+ }
597
+
598
+ public boolean isNotifyReadable (long sig) {
599
+ return getConnection(sig).isNotifyReadable();
600
+ }
601
+
602
+ public boolean isNotifyWritable (long sig) {
603
+ return getConnection(sig).isNotifyWritable();
604
+ }
605
+
606
+ public boolean pauseConnection (long sig) {
607
+ return ((EventableSocketChannel) Connections.get(sig)).pause();
608
+ }
609
+
610
+ public boolean resumeConnection (long sig) {
611
+ return ((EventableSocketChannel) Connections.get(sig)).resume();
612
+ }
613
+
614
+ public boolean isConnectionPaused (long sig) {
615
+ return ((EventableSocketChannel) Connections.get(sig)).isPaused();
616
+ }
617
+
618
+ public long getOutboundDataSize (long sig) {
619
+ return Connections.get(sig).getOutboundDataSize();
620
+ }
621
+
622
+ public int getConnectionCount() {
623
+ return Connections.size() + Acceptors.size();
624
+ }
625
+ }