eventmachine 1.0.0.beta.2-x86-mingw32

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