eventmachine-mkroman 1.3.0.dev.1

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 (182) 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 +2243 -0
  37. data/ext/ed.h +463 -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 +291 -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 +1643 -0
  52. data/ext/ssl.cpp +701 -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 +802 -0
  70. data/lib/em/deferrable/pool.rb +2 -0
  71. data/lib/em/deferrable.rb +210 -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/header_and_content.rb +138 -0
  81. data/lib/em/protocols/httpclient.rb +303 -0
  82. data/lib/em/protocols/httpclient2.rb +602 -0
  83. data/lib/em/protocols/line_and_text.rb +125 -0
  84. data/lib/em/protocols/line_protocol.rb +33 -0
  85. data/lib/em/protocols/linetext2.rb +179 -0
  86. data/lib/em/protocols/memcache.rb +331 -0
  87. data/lib/em/protocols/object_protocol.rb +46 -0
  88. data/lib/em/protocols/postgres3.rb +246 -0
  89. data/lib/em/protocols/saslauth.rb +175 -0
  90. data/lib/em/protocols/smtpclient.rb +394 -0
  91. data/lib/em/protocols/smtpserver.rb +666 -0
  92. data/lib/em/protocols/socks4.rb +66 -0
  93. data/lib/em/protocols/stomp.rb +205 -0
  94. data/lib/em/protocols/tcptest.rb +54 -0
  95. data/lib/em/protocols.rb +37 -0
  96. data/lib/em/pure_ruby.rb +1300 -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 +319 -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 +165 -0
  114. data/tests/em_test_helper.rb +198 -0
  115. data/tests/encoded_client.key +54 -0
  116. data/tests/jruby/test_jeventmachine.rb +38 -0
  117. data/tests/test_attach.rb +199 -0
  118. data/tests/test_basic.rb +321 -0
  119. data/tests/test_channel.rb +75 -0
  120. data/tests/test_completion.rb +178 -0
  121. data/tests/test_connection_count.rb +83 -0
  122. data/tests/test_connection_write.rb +35 -0
  123. data/tests/test_defer.rb +35 -0
  124. data/tests/test_deferrable.rb +35 -0
  125. data/tests/test_epoll.rb +141 -0
  126. data/tests/test_error_handler.rb +38 -0
  127. data/tests/test_exc.rb +37 -0
  128. data/tests/test_file_watch.rb +86 -0
  129. data/tests/test_fork.rb +75 -0
  130. data/tests/test_futures.rb +170 -0
  131. data/tests/test_handler_check.rb +35 -0
  132. data/tests/test_hc.rb +155 -0
  133. data/tests/test_httpclient.rb +238 -0
  134. data/tests/test_httpclient2.rb +132 -0
  135. data/tests/test_idle_connection.rb +31 -0
  136. data/tests/test_inactivity_timeout.rb +102 -0
  137. data/tests/test_io_streamer.rb +48 -0
  138. data/tests/test_ipv4.rb +96 -0
  139. data/tests/test_ipv6.rb +107 -0
  140. data/tests/test_iterator.rb +122 -0
  141. data/tests/test_kb.rb +28 -0
  142. data/tests/test_keepalive.rb +113 -0
  143. data/tests/test_line_protocol.rb +33 -0
  144. data/tests/test_ltp.rb +155 -0
  145. data/tests/test_ltp2.rb +332 -0
  146. data/tests/test_many_fds.rb +21 -0
  147. data/tests/test_next_tick.rb +104 -0
  148. data/tests/test_object_protocol.rb +36 -0
  149. data/tests/test_pause.rb +109 -0
  150. data/tests/test_pending_connect_timeout.rb +52 -0
  151. data/tests/test_pool.rb +196 -0
  152. data/tests/test_process_watch.rb +50 -0
  153. data/tests/test_processes.rb +147 -0
  154. data/tests/test_proxy_connection.rb +180 -0
  155. data/tests/test_pure.rb +156 -0
  156. data/tests/test_queue.rb +64 -0
  157. data/tests/test_resolver.rb +129 -0
  158. data/tests/test_running.rb +14 -0
  159. data/tests/test_sasl.rb +46 -0
  160. data/tests/test_send_file.rb +217 -0
  161. data/tests/test_servers.rb +32 -0
  162. data/tests/test_shutdown_hooks.rb +23 -0
  163. data/tests/test_smtpclient.rb +75 -0
  164. data/tests/test_smtpserver.rb +90 -0
  165. data/tests/test_sock_opt.rb +53 -0
  166. data/tests/test_spawn.rb +290 -0
  167. data/tests/test_ssl_args.rb +70 -0
  168. data/tests/test_ssl_dhparam.rb +57 -0
  169. data/tests/test_ssl_ecdh_curve.rb +57 -0
  170. data/tests/test_ssl_extensions.rb +24 -0
  171. data/tests/test_ssl_inline_cert.rb +222 -0
  172. data/tests/test_ssl_methods.rb +31 -0
  173. data/tests/test_ssl_protocols.rb +190 -0
  174. data/tests/test_ssl_verify.rb +108 -0
  175. data/tests/test_stomp.rb +38 -0
  176. data/tests/test_system.rb +46 -0
  177. data/tests/test_threaded_resource.rb +68 -0
  178. data/tests/test_tick_loop.rb +58 -0
  179. data/tests/test_timers.rb +150 -0
  180. data/tests/test_ud.rb +8 -0
  181. data/tests/test_unbind_reason.rb +40 -0
  182. metadata +389 -0
@@ -0,0 +1,1300 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 8 Apr 2006
6
+ #
7
+ # See EventMachine and EventMachine::Connection for documentation and
8
+ # usage examples.
9
+ #
10
+ #----------------------------------------------------------------------------
11
+ #
12
+ # Copyright (C) 2006-07 by Francis Cianfrocca. All Rights Reserved.
13
+ # Gmail: blackhedd
14
+ #
15
+ # This program is free software; you can redistribute it and/or modify
16
+ # it under the terms of either: 1) the GNU General Public License
17
+ # as published by the Free Software Foundation; either version 2 of the
18
+ # License, or (at your option) any later version; or 2) Ruby's License.
19
+ #
20
+ # See the file COPYING for complete licensing information.
21
+ #
22
+ #-------------------------------------------------------------------
23
+ #
24
+ #
25
+
26
+ # TODO List:
27
+ # TCP-connects currently assume non-blocking connect is available- need to
28
+ # degrade automatically on versions of Ruby prior to June 2006.
29
+ #
30
+
31
+ require 'singleton'
32
+ require 'forwardable'
33
+ require 'socket'
34
+ require 'fcntl'
35
+ require 'set'
36
+ require 'openssl'
37
+
38
+ module EventMachine
39
+ # @private
40
+ class Error < Exception; end
41
+ # @private
42
+ class UnknownTimerFired < RuntimeError; end
43
+ # @private
44
+ class Unsupported < RuntimeError; end
45
+ # @private
46
+ class ConnectionError < RuntimeError; end
47
+ # @private
48
+ class ConnectionNotBound < RuntimeError; end
49
+ class InvalidPrivateKey < RuntimeError; end
50
+
51
+ # Older versions of Ruby may not provide the SSLErrorWaitReadable
52
+ # OpenSSL class. Create an error class to act as a "proxy".
53
+ if defined?(OpenSSL::SSL::SSLErrorWaitReadable)
54
+ SSLConnectionWaitReadable = OpenSSL::SSL::SSLErrorWaitReadable
55
+ else
56
+ SSLConnectionWaitReadable = IO::WaitReadable
57
+ end
58
+
59
+ # Older versions of Ruby may not provide the SSLErrorWaitWritable
60
+ # OpenSSL class. Create an error class to act as a "proxy".
61
+ if defined?(OpenSSL::SSL::SSLErrorWaitWritable)
62
+ SSLConnectionWaitWritable = OpenSSL::SSL::SSLErrorWaitWritable
63
+ else
64
+ SSLConnectionWaitWritable = IO::WaitWritable
65
+ end
66
+ end
67
+
68
+ module EventMachine
69
+ class CertificateCreator
70
+ attr_reader :cert, :key
71
+
72
+ def initialize
73
+ @key = OpenSSL::PKey::RSA.new(1024)
74
+ public_key = @key.public_key
75
+ subject = "/C=EventMachine/O=EventMachine/OU=EventMachine/CN=EventMachine"
76
+ @cert = OpenSSL::X509::Certificate.new
77
+ @cert.subject = @cert.issuer = OpenSSL::X509::Name.parse(subject)
78
+ @cert.not_before = Time.now
79
+ @cert.not_after = Time.now + 365 * 24 * 60 * 60
80
+ @cert.public_key = public_key
81
+ @cert.serial = 0x0
82
+ @cert.version = 2
83
+ factory = OpenSSL::X509::ExtensionFactory.new
84
+ factory.subject_certificate = @cert
85
+ factory.issuer_certificate = @cert
86
+ @cert.extensions = [
87
+ factory.create_extension("basicConstraints","CA:TRUE", true),
88
+ factory.create_extension("subjectKeyIdentifier", "hash")
89
+ ]
90
+ @cert.add_extension factory.create_extension("authorityKeyIdentifier", "keyid:always,issuer:always")
91
+ @cert.sign(@key, OpenSSL::Digest::SHA1.new)
92
+ end
93
+ end
94
+
95
+ # @private
96
+ DefaultCertificate = CertificateCreator.new
97
+
98
+ # @private
99
+ DefaultDHKey1024 = OpenSSL::PKey::DH.new <<-_end_of_pem_
100
+ -----BEGIN DH PARAMETERS-----
101
+ MIGHAoGBAJ0lOVy0VIr/JebWn0zDwY2h+rqITFOpdNr6ugsgvkDXuucdcChhYExJ
102
+ AV/ZD2AWPbrTqV76mGRgJg4EddgT1zG0jq3rnFdMj2XzkBYx3BVvfR0Arnby0RHR
103
+ T4h7KZ/2zmjvV+eF8kBUHBJAojUlzxKj4QeO2x20FP9X5xmNUXeDAgEC
104
+ -----END DH PARAMETERS-----
105
+ _end_of_pem_
106
+
107
+ # @private
108
+ DefaultDHKey2048 = OpenSSL::PKey::DH.new <<-_end_of_pem_
109
+ -----BEGIN DH PARAMETERS-----
110
+ MIIBCAKCAQEA7E6kBrYiyvmKAMzQ7i8WvwVk9Y/+f8S7sCTN712KkK3cqd1jhJDY
111
+ JbrYeNV3kUIKhPxWHhObHKpD1R84UpL+s2b55+iMd6GmL7OYmNIT/FccKhTcveab
112
+ VBmZT86BZKYyf45hUF9FOuUM9xPzuK3Vd8oJQvfYMCd7LPC0taAEljQLR4Edf8E6
113
+ YoaOffgTf5qxiwkjnlVZQc3whgnEt9FpVMvQ9eknyeGB5KHfayAc3+hUAvI3/Cr3
114
+ 1bNveX5wInh5GDx1FGhKBZ+s1H+aedudCm7sCgRwv8lKWYGiHzObSma8A86KG+MD
115
+ 7Lo5JquQ3DlBodj3IDyPrxIv96lvRPFtAwIBAg==
116
+ -----END DH PARAMETERS-----
117
+ _end_of_pem_
118
+ end
119
+
120
+ # @private
121
+ module EventMachine
122
+ class << self
123
+ # This is mostly useful for automated tests.
124
+ # Return a distinctive symbol so the caller knows whether he's dealing
125
+ # with an extension or with a pure-Ruby library.
126
+ # @private
127
+ def library_type
128
+ :pure_ruby
129
+ end
130
+
131
+ # @private
132
+ def initialize_event_machine
133
+ Reactor.instance.initialize_for_run
134
+ end
135
+
136
+ # Changed 04Oct06: intervals from the caller are now in milliseconds, but our native-ruby
137
+ # processor still wants them in seconds.
138
+ # @private
139
+ def add_oneshot_timer interval
140
+ Reactor.instance.install_oneshot_timer(interval.to_f / 1000)
141
+ end
142
+
143
+ # @private
144
+ def run_machine
145
+ Reactor.instance.run
146
+ end
147
+
148
+ # @private
149
+ def release_machine
150
+ end
151
+
152
+
153
+ def stopping?
154
+ return Reactor.instance.stop_scheduled
155
+ end
156
+
157
+ # @private
158
+ def stop
159
+ Reactor.instance.stop
160
+ end
161
+
162
+ # @private
163
+ def connect_server host, port
164
+ bind_connect_server nil, nil, host, port
165
+ end
166
+
167
+ # @private
168
+ def bind_connect_server bind_addr, bind_port, host, port
169
+ EvmaTCPClient.connect(bind_addr, bind_port, host, port).uuid
170
+ end
171
+
172
+ # @private
173
+ def send_data target, data, datalength
174
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
175
+ selectable.send_data data
176
+ end
177
+
178
+ # @private
179
+ def close_connection target, after_writing
180
+ selectable = Reactor.instance.get_selectable( target )
181
+ selectable.schedule_close after_writing if selectable
182
+ end
183
+
184
+ # @private
185
+ def start_tcp_server host, port
186
+ (s = EvmaTCPServer.start_server host, port) or raise "no acceptor"
187
+ s.uuid
188
+ end
189
+
190
+ # @private
191
+ def stop_tcp_server sig
192
+ s = Reactor.instance.get_selectable(sig)
193
+ s.schedule_close
194
+ end
195
+
196
+ # @private
197
+ def start_unix_server chain
198
+ (s = EvmaUNIXServer.start_server chain) or raise "no acceptor"
199
+ s.uuid
200
+ end
201
+
202
+ # @private
203
+ def connect_unix_server chain
204
+ EvmaUNIXClient.connect(chain).uuid
205
+ end
206
+
207
+ # @private
208
+ def signal_loopbreak
209
+ Reactor.instance.signal_loopbreak
210
+ end
211
+
212
+ # @private
213
+ def get_peername sig
214
+ selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_peername target"
215
+ selectable.get_peername
216
+ end
217
+
218
+ # @private
219
+ def get_sockname sig
220
+ selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_sockname target"
221
+ selectable.get_sockname
222
+ end
223
+
224
+ # @private
225
+ def open_udp_socket host, port
226
+ EvmaUDPSocket.create(host, port).uuid
227
+ end
228
+
229
+ # This is currently only for UDP!
230
+ # We need to make it work with unix-domain sockets as well.
231
+ # @private
232
+ def send_datagram target, data, datalength, host, port
233
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
234
+ selectable.send_datagram data, Socket::pack_sockaddr_in(port, host)
235
+ end
236
+
237
+
238
+ # Sets reactor quantum in milliseconds. The underlying Reactor function wants a (possibly
239
+ # fractional) number of seconds.
240
+ # @private
241
+ def set_timer_quantum interval
242
+ Reactor.instance.set_timer_quantum(( 1.0 * interval) / 1000.0)
243
+ end
244
+
245
+ # This method is a harmless no-op in the pure-Ruby implementation. This is intended to ensure
246
+ # that user code behaves properly across different EM implementations.
247
+ # @private
248
+ def epoll
249
+ end
250
+
251
+ # @private
252
+ def ssl?
253
+ true
254
+ end
255
+
256
+ def tls_parm_set?(parm)
257
+ !(parm.nil? || parm.empty?)
258
+ end
259
+
260
+ # This method takes a series of positional arguments for specifying such
261
+ # things as private keys and certificate chains. It's expected that the
262
+ # parameter list will grow as we add more supported features. ALL of these
263
+ # parameters are optional, and can be specified as empty or nil strings.
264
+ # @private
265
+ def set_tls_parms signature, priv_key_path, priv_key, priv_key_pass, cert_chain_path, cert, verify_peer, fail_if_no_peer_cert, sni_hostname, cipher_list, ecdh_curve, dhparam, protocols_bitmask
266
+ bitmask = protocols_bitmask
267
+ ssl_options = OpenSSL::SSL::OP_ALL
268
+ ssl_options |= OpenSSL::SSL::OP_NO_SSLv2 if defined?(OpenSSL::SSL::OP_NO_SSLv2) && EM_PROTO_SSLv2 & bitmask == 0
269
+ ssl_options |= OpenSSL::SSL::OP_NO_SSLv3 if defined?(OpenSSL::SSL::OP_NO_SSLv3) && EM_PROTO_SSLv3 & bitmask == 0
270
+ ssl_options |= OpenSSL::SSL::OP_NO_TLSv1 if defined?(OpenSSL::SSL::OP_NO_TLSv1) && EM_PROTO_TLSv1 & bitmask == 0
271
+ ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_1 if defined?(OpenSSL::SSL::OP_NO_TLSv1_1) && EM_PROTO_TLSv1_1 & bitmask == 0
272
+ ssl_options |= OpenSSL::SSL::OP_NO_TLSv1_2 if defined?(OpenSSL::SSL::OP_NO_TLSv1_2) && EM_PROTO_TLSv1_2 & bitmask == 0
273
+ @tls_parms ||= {}
274
+ @tls_parms[signature] = {
275
+ :verify_peer => verify_peer,
276
+ :fail_if_no_peer_cert => fail_if_no_peer_cert,
277
+ :ssl_options => ssl_options
278
+ }
279
+ @tls_parms[signature][:priv_key] = File.read(priv_key_path) if tls_parm_set?(priv_key_path)
280
+ @tls_parms[signature][:priv_key] = priv_key if tls_parm_set?(priv_key)
281
+ @tls_parms[signature][:priv_key_pass] = priv_key_pass if tls_parm_set?(priv_key_pass)
282
+ @tls_parms[signature][:cert_chain] = File.read(cert_chain_path) if tls_parm_set?(cert_chain_path)
283
+ @tls_parms[signature][:cert_chain] = cert if tls_parm_set?(cert_chain)
284
+ @tls_parms[signature][:sni_hostname] = sni_hostname if tls_parm_set?(sni_hostname)
285
+ @tls_parms[signature][:cipher_list] = cipher_list.gsub(/,\s*/, ':') if tls_parm_set?(cipher_list)
286
+ @tls_parms[signature][:dhparam] = File.read(dhparam) if tls_parm_set?(dhparam)
287
+ @tls_parms[signature][:ecdh_curve] = ecdh_curve if tls_parm_set?(ecdh_curve)
288
+ end
289
+
290
+ def start_tls signature
291
+ selectable = Reactor.instance.get_selectable(signature) or raise "unknown io selectable for start_tls"
292
+ tls_parms = @tls_parms[signature]
293
+ ctx = OpenSSL::SSL::SSLContext.new
294
+ ctx.options = tls_parms[:ssl_options]
295
+ ctx.cert = DefaultCertificate.cert
296
+ ctx.key = DefaultCertificate.key
297
+ ctx.cert_store = OpenSSL::X509::Store.new
298
+ ctx.cert_store.set_default_paths
299
+ ctx.cert = OpenSSL::X509::Certificate.new(tls_parms[:cert_chain]) if tls_parms[:cert_chain]
300
+ if tls_parms[:priv_key_pass]!=nil
301
+ ctx.key = OpenSSL::PKey::RSA.new(tls_parms[:priv_key],tls_parms[:priv_key_pass]) if tls_parms[:priv_key]
302
+ else
303
+ ctx.key = OpenSSL::PKey::RSA.new(tls_parms[:priv_key]) if tls_parms[:priv_key]
304
+ end
305
+ verify_mode = OpenSSL::SSL::VERIFY_NONE
306
+ if tls_parms[:verify_peer]
307
+ verify_mode |= OpenSSL::SSL::VERIFY_PEER
308
+ end
309
+ if tls_parms[:fail_if_no_peer_cert]
310
+ verify_mode |= OpenSSL::SSL::VERIFY_FAIL_IF_NO_PEER_CERT
311
+ end
312
+ ctx.verify_mode = verify_mode
313
+ ctx.servername_cb = Proc.new do |_, server_name|
314
+ tls_parms[:server_name] = server_name
315
+ nil
316
+ end
317
+ ctx.ciphers = tls_parms[:cipher_list] if tls_parms[:cipher_list]
318
+ if selectable.is_server
319
+ ctx.tmp_dh_callback = Proc.new do |_, _, key_length|
320
+ if tls_parms[:dhparam]
321
+ OpenSSL::PKey::DH.new(tls_parms[:dhparam])
322
+ else
323
+ case key_length
324
+ when 1024 then DefaultDHKey1024
325
+ when 2048 then DefaultDHKey2048
326
+ else
327
+ nil
328
+ end
329
+ end
330
+ end
331
+ if tls_parms[:ecdh_curve] && ctx.respond_to?(:tmp_ecdh_callback)
332
+ ctx.tmp_ecdh_callback = Proc.new do
333
+ OpenSSL::PKey::EC.new(tls_parms[:ecdh_curve])
334
+ end
335
+ end
336
+ end
337
+ ssl_io = OpenSSL::SSL::SSLSocket.new(selectable, ctx)
338
+ ssl_io.sync_close = true
339
+ if tls_parms[:sni_hostname]
340
+ ssl_io.hostname = tls_parms[:sni_hostname] if ssl_io.respond_to?(:hostname=)
341
+ end
342
+ begin
343
+ selectable.is_server ? ssl_io.accept_nonblock : ssl_io.connect_nonblock
344
+ rescue; end
345
+ selectable.io = ssl_io
346
+ end
347
+
348
+ def get_peer_cert signature
349
+ selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_peer_cert target"
350
+ if selectable.io.respond_to?(:peer_cert) && selectable.io.peer_cert
351
+ selectable.io.peer_cert.to_pem
352
+ else
353
+ nil
354
+ end
355
+ end
356
+
357
+ def get_cipher_name signature
358
+ selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_name target"
359
+ selectable.io.respond_to?(:cipher) ? selectable.io.cipher[0] : nil
360
+ end
361
+
362
+ def get_cipher_protocol signature
363
+ selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_protocol target"
364
+ selectable.io.respond_to?(:cipher) ? selectable.io.cipher[1] : nil
365
+ end
366
+
367
+ def get_cipher_bits signature
368
+ selectable = Reactor.instance.get_selectable(signature) or raise "unknown get_cipher_bits target"
369
+ selectable.io.respond_to?(:cipher) ? selectable.io.cipher[2] : nil
370
+ end
371
+
372
+ def get_sni_hostname signature
373
+ @tls_parms ||= {}
374
+ if @tls_parms[signature]
375
+ @tls_parms[signature][:server_name]
376
+ else
377
+ nil
378
+ end
379
+ end
380
+
381
+ # This method is a no-op in the pure-Ruby implementation. We simply return Ruby's built-in
382
+ # per-process file-descriptor limit.
383
+ # @private
384
+ def set_rlimit_nofile n
385
+ 1024
386
+ end
387
+
388
+ # This method is a harmless no-op in pure Ruby, which doesn't have a built-in limit
389
+ # on the number of available timers.
390
+ # @private
391
+ def set_max_timer_count n
392
+ end
393
+
394
+ # @private
395
+ def get_sock_opt signature, level, optname
396
+ selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_sock_opt target"
397
+ selectable.getsockopt level, optname
398
+ end
399
+
400
+ # @private
401
+ def set_sock_opt signature, level, optname, optval
402
+ selectable = Reactor.instance.get_selectable( signature ) or raise "unknown set_sock_opt target"
403
+ selectable.setsockopt level, optname, optval
404
+ end
405
+
406
+ # @private
407
+ def send_file_data sig, filename
408
+ sz = File.size(filename)
409
+ raise "file too large" if sz > 32*1024
410
+ data =
411
+ begin
412
+ File.read filename
413
+ rescue
414
+ ""
415
+ end
416
+ send_data sig, data, data.length
417
+ end
418
+
419
+ # @private
420
+ def get_outbound_data_size sig
421
+ r = Reactor.instance.get_selectable( sig ) or raise "unknown get_outbound_data_size target"
422
+ r.get_outbound_data_size
423
+ end
424
+
425
+ # @private
426
+ def read_keyboard
427
+ EvmaKeyboard.open.uuid
428
+ end
429
+
430
+ # @private
431
+ def set_comm_inactivity_timeout sig, tm
432
+ r = Reactor.instance.get_selectable( sig ) or raise "unknown set_comm_inactivity_timeout target"
433
+ r.set_inactivity_timeout tm
434
+ end
435
+
436
+ # @private
437
+ def set_pending_connect_timeout sig, tm
438
+ # Needs to be implemented. Currently a no-op stub to allow
439
+ # certain software to operate with the EM pure-ruby.
440
+ end
441
+
442
+ # @private
443
+ def report_connection_error_status signature
444
+ get_sock_opt(signature, Socket::SOL_SOCKET, Socket::SO_ERROR).int
445
+ end
446
+ end
447
+ end
448
+
449
+ module EventMachine
450
+ # @private
451
+ class Connection
452
+ # @private
453
+ def get_outbound_data_size
454
+ EventMachine::get_outbound_data_size @signature
455
+ end
456
+ end
457
+ end
458
+
459
+ module EventMachine
460
+
461
+ # Factored out so we can substitute other implementations
462
+ # here if desired, such as the one in ActiveRBAC.
463
+ # @private
464
+ module UuidGenerator
465
+ def self.generate
466
+ @ix ||= 0
467
+ @ix += 1
468
+ end
469
+ end
470
+ end
471
+
472
+
473
+ module EventMachine
474
+ # @private
475
+ TimerFired = 100
476
+ # @private
477
+ ConnectionData = 101
478
+ # @private
479
+ ConnectionUnbound = 102
480
+ # @private
481
+ ConnectionAccepted = 103
482
+ # @private
483
+ ConnectionCompleted = 104
484
+ # @private
485
+ LoopbreakSignalled = 105
486
+ # @private
487
+ ConnectionNotifyReadable = 106
488
+ # @private
489
+ ConnectionNotifyWritable = 107
490
+ # @private
491
+ SslHandshakeCompleted = 108
492
+ # @private
493
+ SslVerify = 109
494
+ # @private
495
+ EM_PROTO_SSLv2 = 2
496
+ # @private
497
+ EM_PROTO_SSLv3 = 4
498
+ # @private
499
+ EM_PROTO_TLSv1 = 8
500
+ # @private
501
+ EM_PROTO_TLSv1_1 = 16
502
+ # @private
503
+ EM_PROTO_TLSv1_2 = 32
504
+ end
505
+
506
+ module EventMachine
507
+ # @private
508
+ class Reactor
509
+ include Singleton
510
+
511
+ HeartbeatInterval = 2
512
+
513
+ attr_reader :current_loop_time, :stop_scheduled
514
+
515
+ def initialize
516
+ initialize_for_run
517
+ end
518
+
519
+ def get_timer_count
520
+ @timers.size
521
+ end
522
+
523
+ def install_oneshot_timer interval
524
+ uuid = UuidGenerator::generate
525
+ #@timers << [Time.now + interval, uuid]
526
+ #@timers.sort! {|a,b| a.first <=> b.first}
527
+ @timers.add([Time.now + interval, uuid])
528
+ uuid
529
+ end
530
+
531
+ # Called before run, this is a good place to clear out arrays
532
+ # with cruft that may be left over from a previous run.
533
+ # @private
534
+ def initialize_for_run
535
+ @running = false
536
+ @stop_scheduled = false
537
+ @selectables ||= {}; @selectables.clear
538
+ @timers = SortedSet.new # []
539
+ set_timer_quantum(0.1)
540
+ @current_loop_time = Time.now
541
+ @next_heartbeat = @current_loop_time + HeartbeatInterval
542
+ end
543
+
544
+ def add_selectable io
545
+ @selectables[io.uuid] = io
546
+ end
547
+
548
+ def get_selectable uuid
549
+ @selectables[uuid]
550
+ end
551
+
552
+ def run
553
+ raise Error.new( "already running" ) if @running
554
+ @running = true
555
+
556
+ begin
557
+ open_loopbreaker
558
+
559
+ loop {
560
+ @current_loop_time = Time.now
561
+
562
+ break if @stop_scheduled
563
+ run_timers
564
+ break if @stop_scheduled
565
+ crank_selectables
566
+ break if @stop_scheduled
567
+ run_heartbeats
568
+ }
569
+ ensure
570
+ close_loopbreaker
571
+ @selectables.each {|k, io| io.close}
572
+ @selectables.clear
573
+
574
+ @running = false
575
+ end
576
+
577
+ end
578
+
579
+ def run_timers
580
+ timers_to_delete = []
581
+ @timers.each {|t|
582
+ if t.first <= @current_loop_time
583
+ #@timers.delete t
584
+ timers_to_delete << t
585
+ EventMachine::event_callback "", TimerFired, t.last
586
+ else
587
+ break
588
+ end
589
+ }
590
+ timers_to_delete.map{|c| @timers.delete c}
591
+ timers_to_delete = nil
592
+ #while @timers.length > 0 and @timers.first.first <= now
593
+ # t = @timers.shift
594
+ # EventMachine::event_callback "", TimerFired, t.last
595
+ #end
596
+ end
597
+
598
+ def run_heartbeats
599
+ if @next_heartbeat <= @current_loop_time
600
+ @next_heartbeat = @current_loop_time + HeartbeatInterval
601
+ @selectables.each {|k,io| io.heartbeat}
602
+ end
603
+ end
604
+
605
+ def crank_selectables
606
+ #$stderr.write 'R'
607
+
608
+ readers = @selectables.values.select {|io| io.select_for_reading?}
609
+ writers = @selectables.values.select {|io| io.select_for_writing?}
610
+
611
+ s = select( readers, writers, nil, @timer_quantum)
612
+
613
+ s and s[1] and s[1].each {|w| w.eventable_write }
614
+ s and s[0] and s[0].each {|r| r.eventable_read }
615
+
616
+ @selectables.delete_if {|k,io|
617
+ if io.close_scheduled?
618
+ io.close
619
+ begin
620
+ EventMachine::event_callback io.uuid, ConnectionUnbound, nil
621
+ rescue ConnectionNotBound; end
622
+ true
623
+ end
624
+ }
625
+ end
626
+
627
+ # #stop
628
+ def stop
629
+ raise Error.new( "not running") unless @running
630
+ @stop_scheduled = true
631
+ end
632
+
633
+ def open_loopbreaker
634
+ # Can't use an IO.pipe because they can't be set nonselectable in Windows.
635
+ # Pick a random localhost UDP port.
636
+ #@loopbreak_writer.close if @loopbreak_writer
637
+ #rd,@loopbreak_writer = IO.pipe
638
+ @loopbreak_reader = UDPSocket.new
639
+ @loopbreak_writer = UDPSocket.new
640
+ bound = false
641
+ 100.times {
642
+ @loopbreak_port = rand(10000) + 40000
643
+ begin
644
+ @loopbreak_reader.bind "127.0.0.1", @loopbreak_port
645
+ bound = true
646
+ break
647
+ rescue
648
+ end
649
+ }
650
+ raise "Unable to bind Loopbreaker" unless bound
651
+ LoopbreakReader.new(@loopbreak_reader)
652
+ end
653
+
654
+ def close_loopbreaker
655
+ @loopbreak_writer.close
656
+ @loopbreak_writer = nil
657
+ end
658
+
659
+ def signal_loopbreak
660
+ begin
661
+ @loopbreak_writer.send('+',0,"127.0.0.1",@loopbreak_port) if @loopbreak_writer
662
+ rescue IOError; end
663
+ end
664
+
665
+ def set_timer_quantum interval_in_seconds
666
+ @timer_quantum = interval_in_seconds
667
+ end
668
+
669
+ end
670
+
671
+ end
672
+
673
+ # @private
674
+ class IO
675
+ extend Forwardable
676
+ def_delegator :@my_selectable, :close_scheduled?
677
+ def_delegator :@my_selectable, :select_for_reading?
678
+ def_delegator :@my_selectable, :select_for_writing?
679
+ def_delegator :@my_selectable, :eventable_read
680
+ def_delegator :@my_selectable, :eventable_write
681
+ def_delegator :@my_selectable, :uuid
682
+ def_delegator :@my_selectable, :is_server
683
+ def_delegator :@my_selectable, :is_server=
684
+ def_delegator :@my_selectable, :send_data
685
+ def_delegator :@my_selectable, :schedule_close
686
+ def_delegator :@my_selectable, :get_peername
687
+ def_delegator :@my_selectable, :get_sockname
688
+ def_delegator :@my_selectable, :send_datagram
689
+ def_delegator :@my_selectable, :get_outbound_data_size
690
+ def_delegator :@my_selectable, :set_inactivity_timeout
691
+ def_delegator :@my_selectable, :heartbeat
692
+ def_delegator :@my_selectable, :io
693
+ def_delegator :@my_selectable, :io=
694
+ end
695
+
696
+ module EventMachine
697
+ # @private
698
+ class Selectable
699
+
700
+ attr_accessor :io, :is_server
701
+ attr_reader :uuid
702
+
703
+ def initialize io
704
+ @io = io
705
+ @uuid = UuidGenerator.generate
706
+ @is_server = false
707
+ @last_activity = Reactor.instance.current_loop_time
708
+
709
+ if defined?(Fcntl::F_GETFL)
710
+ m = @io.fcntl(Fcntl::F_GETFL, 0)
711
+ @io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK | m)
712
+ else
713
+ # Windows doesn't define F_GETFL.
714
+ # It's not very reliable about setting descriptors nonblocking either.
715
+ begin
716
+ s = Socket.for_fd(@io.fileno)
717
+ s.fcntl( Fcntl::F_SETFL, Fcntl::O_NONBLOCK )
718
+ rescue Errno::EINVAL, Errno::EBADF
719
+ warn "Serious error: unable to set descriptor non-blocking"
720
+ end
721
+ end
722
+ # TODO, should set CLOEXEC on Unix?
723
+
724
+ @close_scheduled = false
725
+ @close_requested = false
726
+
727
+ se = self; @io.instance_eval { @my_selectable = se }
728
+ Reactor.instance.add_selectable @io
729
+ end
730
+
731
+ def close_scheduled?
732
+ @close_scheduled
733
+ end
734
+
735
+ def select_for_reading?
736
+ false
737
+ end
738
+
739
+ def select_for_writing?
740
+ false
741
+ end
742
+
743
+ def get_peername
744
+ nil
745
+ end
746
+
747
+ def get_sockname
748
+ nil
749
+ end
750
+
751
+ def set_inactivity_timeout tm
752
+ @inactivity_timeout = tm
753
+ end
754
+
755
+ def heartbeat
756
+ end
757
+
758
+ def schedule_close(after_writing=false)
759
+ if after_writing
760
+ @close_requested = true
761
+ else
762
+ @close_scheduled = true
763
+ end
764
+ end
765
+ end
766
+
767
+ end
768
+
769
+ module EventMachine
770
+ # @private
771
+ class StreamObject < Selectable
772
+ def initialize io
773
+ super io
774
+ @outbound_q = []
775
+ end
776
+
777
+ # If we have to close, or a close-after-writing has been requested,
778
+ # then don't read any more data.
779
+ def select_for_reading?
780
+ true unless (@close_scheduled || @close_requested)
781
+ end
782
+
783
+ # If we have to close, don't select for writing.
784
+ # Otherwise, see if the protocol is ready to close.
785
+ # If not, see if he has data to send.
786
+ # If a close-after-writing has been requested and the outbound queue
787
+ # is empty, convert the status to close_scheduled.
788
+ def select_for_writing?
789
+ unless @close_scheduled
790
+ if @outbound_q.empty?
791
+ @close_scheduled = true if @close_requested
792
+ false
793
+ else
794
+ true
795
+ end
796
+ end
797
+ end
798
+
799
+ # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
800
+ # If we have it, then we can read multiple times safely to improve
801
+ # performance.
802
+ # The last-activity clock ASSUMES that we only come here when we
803
+ # have selected readable.
804
+ # TODO, coalesce multiple reads into a single event.
805
+ # TODO, do the function check somewhere else and cache it.
806
+ def eventable_read
807
+ @last_activity = Reactor.instance.current_loop_time
808
+ begin
809
+ if io.respond_to?(:read_nonblock)
810
+ 10.times {
811
+ data = io.read_nonblock(4096)
812
+ EventMachine::event_callback uuid, ConnectionData, data
813
+ }
814
+ else
815
+ data = io.sysread(4096)
816
+ EventMachine::event_callback uuid, ConnectionData, data
817
+ end
818
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK, SSLConnectionWaitReadable
819
+ # no-op
820
+ rescue Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError, Errno::EPIPE, OpenSSL::SSL::SSLError
821
+ @close_scheduled = true
822
+ EventMachine::event_callback uuid, ConnectionUnbound, nil
823
+ end
824
+
825
+ end
826
+
827
+ # Provisional implementation. Will be re-implemented in subclasses.
828
+ # TODO: Complete this implementation. As it stands, this only writes
829
+ # a single packet per cycle. Highly inefficient, but required unless
830
+ # we're running on a Ruby with proper nonblocking I/O (Ruby 1.8.4
831
+ # built from sources from May 25, 2006 or newer).
832
+ # We need to improve the loop so it writes multiple times, however
833
+ # not more than a certain number of bytes per cycle, otherwise
834
+ # one busy connection could hog output buffers and slow down other
835
+ # connections. Also we should coalesce small writes.
836
+ # URGENT TODO: Coalesce small writes. They are a performance killer.
837
+ # The last-activity recorder ASSUMES we'll only come here if we've
838
+ # selected writable.
839
+ def eventable_write
840
+ # coalesce the outbound array here, perhaps
841
+ @last_activity = Reactor.instance.current_loop_time
842
+ while data = @outbound_q.shift do
843
+ begin
844
+ data = data.to_s
845
+ w = if io.respond_to?(:write_nonblock)
846
+ io.write_nonblock data
847
+ else
848
+ io.syswrite data
849
+ end
850
+
851
+ if w < data.length
852
+ @outbound_q.unshift data[w..-1]
853
+ break
854
+ end
855
+ rescue Errno::EAGAIN, SSLConnectionWaitReadable, SSLConnectionWaitWritable
856
+ @outbound_q.unshift data
857
+ break
858
+ rescue EOFError, Errno::ECONNRESET, Errno::ECONNREFUSED, Errno::EPIPE, OpenSSL::SSL::SSLError
859
+ @close_scheduled = true
860
+ @outbound_q.clear
861
+ end
862
+ end
863
+
864
+ end
865
+
866
+ # #send_data
867
+ def send_data data
868
+ # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
869
+ unless @close_scheduled or @close_requested or !data or data.length <= 0
870
+ @outbound_q << data.to_s
871
+ end
872
+ end
873
+
874
+ # #get_peername
875
+ # This is defined in the normal way on connected stream objects.
876
+ # Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants.
877
+ # We could also use a convenience method that did the unpacking automatically.
878
+ def get_peername
879
+ io.getpeername
880
+ end
881
+
882
+ # #get_sockname
883
+ # This is defined in the normal way on connected stream objects.
884
+ # Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants.
885
+ # We could also use a convenience method that did the unpacking automatically.
886
+ def get_sockname
887
+ io.getsockname
888
+ end
889
+
890
+ # #get_outbound_data_size
891
+ def get_outbound_data_size
892
+ @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
893
+ end
894
+
895
+ def heartbeat
896
+ if @inactivity_timeout and @inactivity_timeout > 0 and (@last_activity + @inactivity_timeout) < Reactor.instance.current_loop_time
897
+ schedule_close true
898
+ end
899
+ end
900
+ end
901
+
902
+
903
+ end
904
+
905
+
906
+ #--------------------------------------------------------------
907
+
908
+
909
+
910
+ module EventMachine
911
+ # @private
912
+ class EvmaTCPClient < StreamObject
913
+
914
+ def self.connect bind_addr, bind_port, host, port
915
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
916
+ sd.bind( Socket.pack_sockaddr_in( bind_port, bind_addr )) if bind_addr
917
+
918
+ begin
919
+ # TODO, this assumes a current Ruby snapshot.
920
+ # We need to degrade to a nonblocking connect otherwise.
921
+ sd.connect_nonblock( Socket.pack_sockaddr_in( port, host ))
922
+ rescue Errno::ECONNREFUSED, Errno::EINPROGRESS
923
+ end
924
+ EvmaTCPClient.new sd
925
+ end
926
+
927
+ def initialize io
928
+ super
929
+ @pending = true
930
+ @handshake_complete = false
931
+ end
932
+
933
+ def ready?
934
+ if RUBY_PLATFORM =~ /linux/
935
+ io.getsockopt(Socket::SOL_TCP, Socket::TCP_INFO).unpack("i").first == 1 # TCP_ESTABLISHED
936
+ else
937
+ io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first == 0 # NO ERROR
938
+ end
939
+ end
940
+
941
+ def handshake_complete?
942
+ if !@handshake_complete && io.respond_to?(:state)
943
+ if io.state =~ /^SSLOK/
944
+ @handshake_complete = true
945
+ EventMachine::event_callback uuid, SslHandshakeCompleted, ""
946
+ EventMachine::event_callback uuid, SslVerify, io.peer_cert.to_pem if io.peer_cert
947
+ end
948
+ else
949
+ @handshake_complete = true
950
+ end
951
+ @handshake_complete
952
+ end
953
+
954
+ def pending?
955
+ handshake_complete?
956
+ if @pending
957
+ if ready?
958
+ @pending = false
959
+ EventMachine::event_callback uuid, ConnectionCompleted, ""
960
+ end
961
+ end
962
+ @pending
963
+ end
964
+
965
+ def select_for_writing?
966
+ pending?
967
+ super
968
+ end
969
+
970
+ def select_for_reading?
971
+ pending?
972
+ super
973
+ end
974
+ end
975
+ end
976
+
977
+
978
+
979
+ module EventMachine
980
+ # @private
981
+ class EvmaKeyboard < StreamObject
982
+
983
+ def self.open
984
+ EvmaKeyboard.new STDIN
985
+ end
986
+
987
+
988
+ def initialize io
989
+ super
990
+ end
991
+
992
+
993
+ def select_for_writing?
994
+ false
995
+ end
996
+
997
+ def select_for_reading?
998
+ true
999
+ end
1000
+
1001
+
1002
+ end
1003
+ end
1004
+
1005
+
1006
+
1007
+ module EventMachine
1008
+ # @private
1009
+ class EvmaUNIXClient < StreamObject
1010
+
1011
+ def self.connect chain
1012
+ sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
1013
+ begin
1014
+ # TODO, this assumes a current Ruby snapshot.
1015
+ # We need to degrade to a nonblocking connect otherwise.
1016
+ sd.connect_nonblock( Socket.pack_sockaddr_un( chain ))
1017
+ rescue Errno::EINPROGRESS
1018
+ end
1019
+ EvmaUNIXClient.new sd
1020
+ end
1021
+
1022
+
1023
+ def initialize io
1024
+ super
1025
+ @pending = true
1026
+ end
1027
+
1028
+
1029
+ def select_for_writing?
1030
+ @pending ? true : super
1031
+ end
1032
+
1033
+ def select_for_reading?
1034
+ @pending ? false : super
1035
+ end
1036
+
1037
+ def eventable_write
1038
+ if @pending
1039
+ @pending = false
1040
+ if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
1041
+ EventMachine::event_callback uuid, ConnectionCompleted, ""
1042
+ end
1043
+ else
1044
+ super
1045
+ end
1046
+ end
1047
+
1048
+
1049
+
1050
+ end
1051
+ end
1052
+
1053
+
1054
+ #--------------------------------------------------------------
1055
+
1056
+ module EventMachine
1057
+ # @private
1058
+ class EvmaTCPServer < Selectable
1059
+
1060
+ # TODO, refactor and unify with EvmaUNIXServer.
1061
+
1062
+ class << self
1063
+ # Versions of ruby 1.8.4 later than May 26 2006 will work properly
1064
+ # with an object of type TCPServer. Prior versions won't so we
1065
+ # play it safe and just build a socket.
1066
+ #
1067
+ def start_server host, port
1068
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
1069
+ sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
1070
+ sd.bind( Socket.pack_sockaddr_in( port, host ))
1071
+ sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
1072
+ EvmaTCPServer.new sd
1073
+ end
1074
+ end
1075
+
1076
+ def initialize io
1077
+ super io
1078
+ end
1079
+
1080
+
1081
+ def select_for_reading?
1082
+ true
1083
+ end
1084
+
1085
+ #--
1086
+ # accept_nonblock returns an array consisting of the accepted
1087
+ # socket and a sockaddr_in which names the peer.
1088
+ # Don't accept more than 10 at a time.
1089
+ def eventable_read
1090
+ begin
1091
+ 10.times {
1092
+ descriptor,peername = io.accept_nonblock
1093
+ sd = EvmaTCPClient.new descriptor
1094
+ sd.is_server = true
1095
+ EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
1096
+ }
1097
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
1098
+ end
1099
+ end
1100
+
1101
+ #--
1102
+ #
1103
+ def schedule_close
1104
+ @close_scheduled = true
1105
+ end
1106
+
1107
+ end
1108
+ end
1109
+
1110
+
1111
+ #--------------------------------------------------------------
1112
+
1113
+ module EventMachine
1114
+ # @private
1115
+ class EvmaUNIXServer < Selectable
1116
+
1117
+ # TODO, refactor and unify with EvmaTCPServer.
1118
+
1119
+ class << self
1120
+ # Versions of ruby 1.8.4 later than May 26 2006 will work properly
1121
+ # with an object of type TCPServer. Prior versions won't so we
1122
+ # play it safe and just build a socket.
1123
+ #
1124
+ def start_server chain
1125
+ sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
1126
+ sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
1127
+ sd.bind( Socket.pack_sockaddr_un( chain ))
1128
+ sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
1129
+ EvmaUNIXServer.new sd
1130
+ end
1131
+ end
1132
+
1133
+ def initialize io
1134
+ super io
1135
+ end
1136
+
1137
+
1138
+ def select_for_reading?
1139
+ true
1140
+ end
1141
+
1142
+ #--
1143
+ # accept_nonblock returns an array consisting of the accepted
1144
+ # socket and a sockaddr_in which names the peer.
1145
+ # Don't accept more than 10 at a time.
1146
+ def eventable_read
1147
+ begin
1148
+ 10.times {
1149
+ descriptor,peername = io.accept_nonblock
1150
+ sd = StreamObject.new descriptor
1151
+ EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
1152
+ }
1153
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
1154
+ end
1155
+ end
1156
+
1157
+ #--
1158
+ #
1159
+ def schedule_close
1160
+ @close_scheduled = true
1161
+ end
1162
+
1163
+ end
1164
+ end
1165
+
1166
+
1167
+
1168
+ #--------------------------------------------------------------
1169
+
1170
+ module EventMachine
1171
+ # @private
1172
+ class LoopbreakReader < Selectable
1173
+
1174
+ def select_for_reading?
1175
+ true
1176
+ end
1177
+
1178
+ def eventable_read
1179
+ io.sysread(128)
1180
+ EventMachine::event_callback "", LoopbreakSignalled, ""
1181
+ end
1182
+
1183
+ end
1184
+ end
1185
+
1186
+
1187
+
1188
+ # @private
1189
+ module EventMachine
1190
+ # @private
1191
+ class DatagramObject < Selectable
1192
+ def initialize io
1193
+ super io
1194
+ @outbound_q = []
1195
+ end
1196
+
1197
+ # #send_datagram
1198
+ def send_datagram data, target
1199
+ # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
1200
+ unless @close_scheduled or @close_requested
1201
+ @outbound_q << [data.to_s, target]
1202
+ end
1203
+ end
1204
+
1205
+ # #select_for_writing?
1206
+ def select_for_writing?
1207
+ unless @close_scheduled
1208
+ if @outbound_q.empty?
1209
+ @close_scheduled = true if @close_requested
1210
+ false
1211
+ else
1212
+ true
1213
+ end
1214
+ end
1215
+ end
1216
+
1217
+ # #select_for_reading?
1218
+ def select_for_reading?
1219
+ true
1220
+ end
1221
+
1222
+ # #get_outbound_data_size
1223
+ def get_outbound_data_size
1224
+ @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
1225
+ end
1226
+
1227
+
1228
+ end
1229
+
1230
+
1231
+ end
1232
+
1233
+
1234
+ module EventMachine
1235
+ # @private
1236
+ class EvmaUDPSocket < DatagramObject
1237
+
1238
+ class << self
1239
+ def create host, port
1240
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
1241
+ sd.bind Socket::pack_sockaddr_in( port, host )
1242
+ EvmaUDPSocket.new sd
1243
+ end
1244
+ end
1245
+
1246
+ # #eventable_write
1247
+ # This really belongs in DatagramObject, but there is some UDP-specific stuff.
1248
+ def eventable_write
1249
+ 40.times {
1250
+ break if @outbound_q.empty?
1251
+ begin
1252
+ data,target = @outbound_q.first
1253
+
1254
+ # This damn better be nonblocking.
1255
+ io.send data.to_s, 0, target
1256
+
1257
+ @outbound_q.shift
1258
+ rescue Errno::EAGAIN
1259
+ # It's not been observed in testing that we ever get here.
1260
+ # True to the definition, packets will be accepted and quietly dropped
1261
+ # if the system is under pressure.
1262
+ break
1263
+ rescue EOFError, Errno::ECONNRESET
1264
+ @close_scheduled = true
1265
+ @outbound_q.clear
1266
+ end
1267
+ }
1268
+ end
1269
+
1270
+ # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
1271
+ # If we have it, then we can read multiple times safely to improve
1272
+ # performance.
1273
+ def eventable_read
1274
+ begin
1275
+ if io.respond_to?(:recvfrom_nonblock)
1276
+ 40.times {
1277
+ data,@return_address = io.recvfrom_nonblock(16384)
1278
+ EventMachine::event_callback uuid, ConnectionData, data
1279
+ @return_address = nil
1280
+ }
1281
+ else
1282
+ raise "unimplemented datagram-read operation on this Ruby"
1283
+ end
1284
+ rescue Errno::EAGAIN
1285
+ # no-op
1286
+ rescue Errno::ECONNRESET, EOFError
1287
+ @close_scheduled = true
1288
+ EventMachine::event_callback uuid, ConnectionUnbound, nil
1289
+ end
1290
+ end
1291
+
1292
+ def send_data data
1293
+ send_datagram data, @return_address
1294
+ end
1295
+ end
1296
+ end
1297
+
1298
+ # load base EM api on top, now that we have the underlying pure ruby
1299
+ # implementation defined
1300
+ require 'eventmachine'