sensu-em 2.4.0-x86-mingw32

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 (178) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +21 -0
  3. data/.travis.yml +12 -0
  4. data/.yardopts +7 -0
  5. data/CHANGELOG.md +33 -0
  6. data/GNU +281 -0
  7. data/Gemfile +2 -0
  8. data/LICENSE +60 -0
  9. data/README.md +109 -0
  10. data/Rakefile +20 -0
  11. data/docs/DocumentationGuidesIndex.md +27 -0
  12. data/docs/GettingStarted.md +521 -0
  13. data/docs/old/ChangeLog +211 -0
  14. data/docs/old/DEFERRABLES +246 -0
  15. data/docs/old/EPOLL +141 -0
  16. data/docs/old/INSTALL +13 -0
  17. data/docs/old/KEYBOARD +42 -0
  18. data/docs/old/LEGAL +25 -0
  19. data/docs/old/LIGHTWEIGHT_CONCURRENCY +130 -0
  20. data/docs/old/PURE_RUBY +75 -0
  21. data/docs/old/RELEASE_NOTES +94 -0
  22. data/docs/old/SMTP +4 -0
  23. data/docs/old/SPAWNED_PROCESSES +148 -0
  24. data/docs/old/TODO +8 -0
  25. data/eventmachine.gemspec +37 -0
  26. data/examples/guides/getting_started/01_eventmachine_echo_server.rb +18 -0
  27. data/examples/guides/getting_started/02_eventmachine_echo_server_that_recognizes_exit_command.rb +22 -0
  28. data/examples/guides/getting_started/03_simple_chat_server.rb +149 -0
  29. data/examples/guides/getting_started/04_simple_chat_server_step_one.rb +27 -0
  30. data/examples/guides/getting_started/05_simple_chat_server_step_two.rb +43 -0
  31. data/examples/guides/getting_started/06_simple_chat_server_step_three.rb +98 -0
  32. data/examples/guides/getting_started/07_simple_chat_server_step_four.rb +121 -0
  33. data/examples/guides/getting_started/08_simple_chat_server_step_five.rb +141 -0
  34. data/examples/old/ex_channel.rb +43 -0
  35. data/examples/old/ex_queue.rb +2 -0
  36. data/examples/old/ex_tick_loop_array.rb +15 -0
  37. data/examples/old/ex_tick_loop_counter.rb +32 -0
  38. data/examples/old/helper.rb +2 -0
  39. data/ext/binder.cpp +124 -0
  40. data/ext/binder.h +46 -0
  41. data/ext/cmain.cpp +887 -0
  42. data/ext/ed.cpp +1992 -0
  43. data/ext/ed.h +424 -0
  44. data/ext/em.cpp +2352 -0
  45. data/ext/em.h +253 -0
  46. data/ext/eventmachine.h +128 -0
  47. data/ext/extconf.rb +179 -0
  48. data/ext/fastfilereader/extconf.rb +103 -0
  49. data/ext/fastfilereader/mapper.cpp +214 -0
  50. data/ext/fastfilereader/mapper.h +59 -0
  51. data/ext/fastfilereader/rubymain.cpp +127 -0
  52. data/ext/kb.cpp +79 -0
  53. data/ext/page.cpp +107 -0
  54. data/ext/page.h +51 -0
  55. data/ext/pipe.cpp +347 -0
  56. data/ext/project.h +161 -0
  57. data/ext/rubymain.cpp +1318 -0
  58. data/ext/ssl.cpp +476 -0
  59. data/ext/ssl.h +95 -0
  60. data/java/.classpath +6 -0
  61. data/java/.gitignore +1 -0
  62. data/java/.project +17 -0
  63. data/java/src/com/rubyeventmachine/DatagramPacket.java +13 -0
  64. data/java/src/com/rubyeventmachine/EmReactor.java +531 -0
  65. data/java/src/com/rubyeventmachine/EmReactorException.java +40 -0
  66. data/java/src/com/rubyeventmachine/EventCallback.java +7 -0
  67. data/java/src/com/rubyeventmachine/EventCode.java +26 -0
  68. data/java/src/com/rubyeventmachine/EventableChannel.java +130 -0
  69. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +179 -0
  70. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +405 -0
  71. data/java/src/com/rubyeventmachine/SslBox.java +311 -0
  72. data/lib/em/buftok.rb +110 -0
  73. data/lib/em/callback.rb +58 -0
  74. data/lib/em/channel.rb +64 -0
  75. data/lib/em/completion.rb +304 -0
  76. data/lib/em/connection.rb +716 -0
  77. data/lib/em/deferrable.rb +210 -0
  78. data/lib/em/deferrable/pool.rb +2 -0
  79. data/lib/em/file_watch.rb +73 -0
  80. data/lib/em/future.rb +61 -0
  81. data/lib/em/iterator.rb +231 -0
  82. data/lib/em/messages.rb +66 -0
  83. data/lib/em/pool.rb +151 -0
  84. data/lib/em/process_watch.rb +45 -0
  85. data/lib/em/processes.rb +123 -0
  86. data/lib/em/protocols.rb +37 -0
  87. data/lib/em/protocols/header_and_content.rb +138 -0
  88. data/lib/em/protocols/httpclient.rb +279 -0
  89. data/lib/em/protocols/httpclient2.rb +600 -0
  90. data/lib/em/protocols/line_and_text.rb +125 -0
  91. data/lib/em/protocols/line_protocol.rb +29 -0
  92. data/lib/em/protocols/linetext2.rb +161 -0
  93. data/lib/em/protocols/memcache.rb +331 -0
  94. data/lib/em/protocols/object_protocol.rb +46 -0
  95. data/lib/em/protocols/postgres3.rb +246 -0
  96. data/lib/em/protocols/saslauth.rb +175 -0
  97. data/lib/em/protocols/smtpclient.rb +365 -0
  98. data/lib/em/protocols/smtpserver.rb +643 -0
  99. data/lib/em/protocols/socks4.rb +66 -0
  100. data/lib/em/protocols/stomp.rb +205 -0
  101. data/lib/em/protocols/tcptest.rb +54 -0
  102. data/lib/em/pure_ruby.rb +1017 -0
  103. data/lib/em/queue.rb +71 -0
  104. data/lib/em/resolver.rb +209 -0
  105. data/lib/em/spawnable.rb +84 -0
  106. data/lib/em/streamer.rb +118 -0
  107. data/lib/em/threaded_resource.rb +90 -0
  108. data/lib/em/tick_loop.rb +85 -0
  109. data/lib/em/timers.rb +61 -0
  110. data/lib/em/version.rb +3 -0
  111. data/lib/eventmachine.rb +1553 -0
  112. data/lib/fastfilereaderext.rb +2 -0
  113. data/lib/jeventmachine.rb +321 -0
  114. data/lib/rubyeventmachine.rb +2 -0
  115. data/rakelib/cpp.rake_example +77 -0
  116. data/rakelib/package.rake +98 -0
  117. data/rakelib/test.rake +8 -0
  118. data/tests/client.crt +31 -0
  119. data/tests/client.key +51 -0
  120. data/tests/em_test_helper.rb +64 -0
  121. data/tests/server.crt +36 -0
  122. data/tests/server.key +51 -0
  123. data/tests/test_attach.rb +150 -0
  124. data/tests/test_basic.rb +294 -0
  125. data/tests/test_channel.rb +62 -0
  126. data/tests/test_completion.rb +177 -0
  127. data/tests/test_connection_count.rb +53 -0
  128. data/tests/test_defer.rb +18 -0
  129. data/tests/test_deferrable.rb +35 -0
  130. data/tests/test_epoll.rb +145 -0
  131. data/tests/test_error_handler.rb +38 -0
  132. data/tests/test_exc.rb +28 -0
  133. data/tests/test_file_watch.rb +65 -0
  134. data/tests/test_futures.rb +170 -0
  135. data/tests/test_get_sock_opt.rb +37 -0
  136. data/tests/test_handler_check.rb +35 -0
  137. data/tests/test_hc.rb +155 -0
  138. data/tests/test_httpclient.rb +190 -0
  139. data/tests/test_httpclient2.rb +133 -0
  140. data/tests/test_idle_connection.rb +25 -0
  141. data/tests/test_inactivity_timeout.rb +54 -0
  142. data/tests/test_iterator.rb +97 -0
  143. data/tests/test_kb.rb +34 -0
  144. data/tests/test_line_protocol.rb +33 -0
  145. data/tests/test_ltp.rb +138 -0
  146. data/tests/test_ltp2.rb +288 -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 +102 -0
  150. data/tests/test_pending_connect_timeout.rb +52 -0
  151. data/tests/test_pool.rb +194 -0
  152. data/tests/test_process_watch.rb +48 -0
  153. data/tests/test_processes.rb +128 -0
  154. data/tests/test_proxy_connection.rb +180 -0
  155. data/tests/test_pure.rb +88 -0
  156. data/tests/test_queue.rb +50 -0
  157. data/tests/test_resolver.rb +55 -0
  158. data/tests/test_running.rb +14 -0
  159. data/tests/test_sasl.rb +47 -0
  160. data/tests/test_send_file.rb +217 -0
  161. data/tests/test_servers.rb +33 -0
  162. data/tests/test_set_sock_opt.rb +37 -0
  163. data/tests/test_shutdown_hooks.rb +23 -0
  164. data/tests/test_smtpclient.rb +55 -0
  165. data/tests/test_smtpserver.rb +57 -0
  166. data/tests/test_spawn.rb +293 -0
  167. data/tests/test_ssl_args.rb +78 -0
  168. data/tests/test_ssl_echo_data.rb +60 -0
  169. data/tests/test_ssl_methods.rb +56 -0
  170. data/tests/test_ssl_verify.rb +82 -0
  171. data/tests/test_stomp.rb +37 -0
  172. data/tests/test_system.rb +42 -0
  173. data/tests/test_threaded_resource.rb +53 -0
  174. data/tests/test_tick_loop.rb +59 -0
  175. data/tests/test_timers.rb +123 -0
  176. data/tests/test_ud.rb +8 -0
  177. data/tests/test_unbind_reason.rb +48 -0
  178. metadata +300 -0
@@ -0,0 +1,66 @@
1
+ module EventMachine
2
+ module Protocols
3
+ # Basic SOCKS v4 client implementation
4
+ #
5
+ # Use as you would any regular connection:
6
+ #
7
+ # class MyConn < EM::P::Socks4
8
+ # def post_init
9
+ # send_data("sup")
10
+ # end
11
+ #
12
+ # def receive_data(data)
13
+ # send_data("you said: #{data}")
14
+ # end
15
+ # end
16
+ #
17
+ # EM.connect socks_host, socks_port, MyConn, host, port
18
+ #
19
+ class Socks4 < Connection
20
+ def initialize(host, port)
21
+ @host = Socket.gethostbyname(host).last
22
+ @port = port
23
+ @socks_error_code = nil
24
+ @buffer = ''
25
+ setup_methods
26
+ end
27
+
28
+ def setup_methods
29
+ class << self
30
+ def post_init; socks_post_init; end
31
+ def receive_data(*a); socks_receive_data(*a); end
32
+ end
33
+ end
34
+
35
+ def restore_methods
36
+ class << self
37
+ remove_method :post_init
38
+ remove_method :receive_data
39
+ end
40
+ end
41
+
42
+ def socks_post_init
43
+ header = [4, 1, @port, @host, 0].flatten.pack("CCnA4C")
44
+ send_data(header)
45
+ end
46
+
47
+ def socks_receive_data(data)
48
+ @buffer << data
49
+ return if @buffer.size < 8
50
+
51
+ header_resp = @buffer.slice! 0, 8
52
+ _, r = header_resp.unpack("cc")
53
+ if r != 90
54
+ @socks_error_code = r
55
+ close_connection
56
+ return
57
+ end
58
+
59
+ restore_methods
60
+
61
+ post_init
62
+ receive_data(@buffer) unless @buffer.empty?
63
+ end
64
+ end
65
+ end
66
+ end
@@ -0,0 +1,205 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 15 November 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
+
27
+ module EventMachine
28
+ module Protocols
29
+
30
+ # Implements Stomp (http://docs.codehaus.org/display/STOMP/Protocol).
31
+ #
32
+ # == Usage example
33
+ #
34
+ # module StompClient
35
+ # include EM::Protocols::Stomp
36
+ #
37
+ # def connection_completed
38
+ # connect :login => 'guest', :passcode => 'guest'
39
+ # end
40
+ #
41
+ # def receive_msg msg
42
+ # if msg.command == "CONNECTED"
43
+ # subscribe '/some/topic'
44
+ # else
45
+ # p ['got a message', msg]
46
+ # puts msg.body
47
+ # end
48
+ # end
49
+ # end
50
+ #
51
+ # EM.run{
52
+ # EM.connect 'localhost', 61613, StompClient
53
+ # }
54
+ #
55
+ module Stomp
56
+ include LineText2
57
+
58
+ class Message
59
+ # The command associated with the message, usually 'CONNECTED' or 'MESSAGE'
60
+ attr_accessor :command
61
+ # Hash containing headers such as destination and message-id
62
+ attr_accessor :header
63
+ alias :headers :header
64
+ # Body of the message
65
+ attr_accessor :body
66
+
67
+ # @private
68
+ def initialize
69
+ @header = {}
70
+ @state = :precommand
71
+ @content_length = nil
72
+ end
73
+ # @private
74
+ def consume_line line
75
+ if @state == :precommand
76
+ unless line =~ /\A\s*\Z/
77
+ @command = line
78
+ @state = :headers
79
+ end
80
+ elsif @state == :headers
81
+ if line == ""
82
+ if @content_length
83
+ yield( [:sized_text, @content_length+1] )
84
+ else
85
+ @state = :body
86
+ yield( [:unsized_text] )
87
+ end
88
+ elsif line =~ /\A([^:]+):(.+)\Z/
89
+ k = $1.dup.strip
90
+ v = $2.dup.strip
91
+ @header[k] = v
92
+ if k == "content-length"
93
+ @content_length = v.to_i
94
+ end
95
+ else
96
+ # This is a protocol error. How to signal it?
97
+ end
98
+ elsif @state == :body
99
+ @body = line
100
+ yield( [:dispatch] )
101
+ end
102
+ end
103
+ end
104
+
105
+ # @private
106
+ def send_frame verb, headers={}, body=""
107
+ body = body.to_s
108
+ ary = [verb, "\n"]
109
+ body_bytesize = body.bytesize if body.respond_to? :bytesize
110
+ body_bytesize ||= body.size
111
+ headers.each {|k,v| ary << "#{k}:#{v}\n" }
112
+ ary << "content-length: #{body_bytesize}\n"
113
+ ary << "content-type: text/plain; charset=UTF-8\n" unless headers.has_key? 'content-type'
114
+ ary << "\n"
115
+ ary << body
116
+ ary << "\0"
117
+ send_data ary.join
118
+ end
119
+
120
+ # @private
121
+ def receive_line line
122
+ @stomp_initialized || init_message_reader
123
+ @stomp_message.consume_line(line) {|outcome|
124
+ if outcome.first == :sized_text
125
+ set_text_mode outcome[1]
126
+ elsif outcome.first == :unsized_text
127
+ set_delimiter "\0"
128
+ elsif outcome.first == :dispatch
129
+ receive_msg(@stomp_message) if respond_to?(:receive_msg)
130
+ init_message_reader
131
+ end
132
+ }
133
+ end
134
+
135
+ # @private
136
+ def receive_binary_data data
137
+ @stomp_message.body = data[0..-2]
138
+ receive_msg(@stomp_message) if respond_to?(:receive_msg)
139
+ init_message_reader
140
+ end
141
+
142
+ # @private
143
+ def init_message_reader
144
+ @stomp_initialized = true
145
+ set_delimiter "\n"
146
+ set_line_mode
147
+ @stomp_message = Message.new
148
+ end
149
+
150
+ # Invoked with an incoming Stomp::Message received from the STOMP server
151
+ def receive_msg msg
152
+ # stub, overwrite this in your handler
153
+ end
154
+
155
+ # CONNECT command, for authentication
156
+ #
157
+ # connect :login => 'guest', :passcode => 'guest'
158
+ #
159
+ def connect parms={}
160
+ send_frame "CONNECT", parms
161
+ end
162
+
163
+ # SEND command, for publishing messages to a topic
164
+ #
165
+ # send '/topic/name', 'some message here'
166
+ #
167
+ def send destination, body, parms={}
168
+ send_frame "SEND", parms.merge( :destination=>destination ), body.to_s
169
+ end
170
+
171
+ # SUBSCRIBE command, for subscribing to topics
172
+ #
173
+ # subscribe '/topic/name', false
174
+ #
175
+ def subscribe dest, ack=false
176
+ send_frame "SUBSCRIBE", {:destination=>dest, :ack=>(ack ? "client" : "auto")}
177
+ end
178
+
179
+ # ACK command, for acknowledging receipt of messages
180
+ #
181
+ # module StompClient
182
+ # include EM::P::Stomp
183
+ #
184
+ # def connection_completed
185
+ # connect :login => 'guest', :passcode => 'guest'
186
+ # # subscribe with ack mode
187
+ # subscribe '/some/topic', true
188
+ # end
189
+ #
190
+ # def receive_msg msg
191
+ # if msg.command == "MESSAGE"
192
+ # ack msg.headers['message-id']
193
+ # puts msg.body
194
+ # end
195
+ # end
196
+ # end
197
+ #
198
+ def ack msgid
199
+ send_frame "ACK", 'message-id'=> msgid
200
+ end
201
+
202
+ end
203
+ end
204
+ end
205
+
@@ -0,0 +1,54 @@
1
+ #--
2
+ #
3
+ # Author:: Francis Cianfrocca (gmail: blackhedd)
4
+ # Homepage:: http://rubyeventmachine.com
5
+ # Date:: 16 July 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
+
27
+ module EventMachine
28
+ module Protocols
29
+
30
+ # @private
31
+ class TcpConnectTester < Connection
32
+ include EventMachine::Deferrable
33
+
34
+ def self.test( host, port )
35
+ EventMachine.connect( host, port, self )
36
+ end
37
+
38
+ def post_init
39
+ @start_time = Time.now
40
+ end
41
+
42
+ def connection_completed
43
+ @completed = true
44
+ set_deferred_status :succeeded, (Time.now - @start_time)
45
+ close_connection
46
+ end
47
+
48
+ def unbind
49
+ set_deferred_status :failed, (Time.now - @start_time) unless @completed
50
+ end
51
+ end
52
+
53
+ end
54
+ end
@@ -0,0 +1,1017 @@
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
+
37
+ # @private
38
+ module EventMachine
39
+ class << self
40
+ # This is mostly useful for automated tests.
41
+ # Return a distinctive symbol so the caller knows whether he's dealing
42
+ # with an extension or with a pure-Ruby library.
43
+ # @private
44
+ def library_type
45
+ :pure_ruby
46
+ end
47
+
48
+ # @private
49
+ def initialize_event_machine
50
+ Reactor.instance.initialize_for_run
51
+ end
52
+
53
+ # Changed 04Oct06: intervals from the caller are now in milliseconds, but our native-ruby
54
+ # processor still wants them in seconds.
55
+ # @private
56
+ def add_oneshot_timer interval
57
+ Reactor.instance.install_oneshot_timer(interval / 1000)
58
+ end
59
+
60
+ # @private
61
+ def run_machine
62
+ Reactor.instance.run
63
+ end
64
+
65
+ # @private
66
+ def release_machine
67
+ end
68
+
69
+ # @private
70
+ def stop
71
+ Reactor.instance.stop
72
+ end
73
+
74
+ # @private
75
+ def connect_server host, port
76
+ bind_connect_server nil, nil, host, port
77
+ end
78
+
79
+ # @private
80
+ def bind_connect_server bind_addr, bind_port, host, port
81
+ EvmaTCPClient.connect(bind_addr, bind_port, host, port).uuid
82
+ end
83
+
84
+ # @private
85
+ def send_data target, data, datalength
86
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
87
+ selectable.send_data data
88
+ end
89
+
90
+
91
+ # The extension version does NOT raise any kind of an error if an attempt is made
92
+ # to close a non-existent connection. Not sure whether we should. For now, we'll
93
+ # raise an error here in that case.
94
+ # @private
95
+ def close_connection target, after_writing
96
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown close_connection target"
97
+ selectable.schedule_close after_writing
98
+ end
99
+
100
+ # @private
101
+ def start_tcp_server host, port
102
+ (s = EvmaTCPServer.start_server host, port) or raise "no acceptor"
103
+ s.uuid
104
+ end
105
+
106
+ # @private
107
+ def stop_tcp_server sig
108
+ s = Reactor.instance.get_selectable(sig)
109
+ s.schedule_close
110
+ end
111
+
112
+ # @private
113
+ def start_unix_server chain
114
+ (s = EvmaUNIXServer.start_server chain) or raise "no acceptor"
115
+ s.uuid
116
+ end
117
+
118
+ # @private
119
+ def connect_unix_server chain
120
+ EvmaUNIXClient.connect(chain).uuid
121
+ end
122
+
123
+ # @private
124
+ def signal_loopbreak
125
+ Reactor.instance.signal_loopbreak
126
+ end
127
+
128
+ # @private
129
+ def get_peername sig
130
+ selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_peername target"
131
+ selectable.get_peername
132
+ end
133
+
134
+ # @private
135
+ def open_udp_socket host, port
136
+ EvmaUDPSocket.create(host, port).uuid
137
+ end
138
+
139
+ # This is currently only for UDP!
140
+ # We need to make it work with unix-domain sockets as well.
141
+ # @private
142
+ def send_datagram target, data, datalength, host, port
143
+ selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
144
+ selectable.send_datagram data, Socket::pack_sockaddr_in(port, host)
145
+ end
146
+
147
+
148
+ # Sets reactor quantum in milliseconds. The underlying Reactor function wants a (possibly
149
+ # fractional) number of seconds.
150
+ # @private
151
+ def set_timer_quantum interval
152
+ Reactor.instance.set_timer_quantum(( 1.0 * interval) / 1000.0)
153
+ end
154
+
155
+ # This method is a harmless no-op in the pure-Ruby implementation. This is intended to ensure
156
+ # that user code behaves properly across different EM implementations.
157
+ # @private
158
+ def epoll
159
+ end
160
+
161
+ # This method is not implemented for pure-Ruby implementation
162
+ # @private
163
+ def ssl?
164
+ false
165
+ end
166
+
167
+ # This method is a no-op in the pure-Ruby implementation. We simply return Ruby's built-in
168
+ # per-process file-descriptor limit.
169
+ # @private
170
+ def set_rlimit_nofile n
171
+ 1024
172
+ end
173
+
174
+ # This method is a harmless no-op in pure Ruby, which doesn't have a built-in limit
175
+ # on the number of available timers.
176
+ # @private
177
+ def set_max_timer_count n
178
+ end
179
+
180
+ # @private
181
+ def get_sock_opt signature, level, optname
182
+ selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_peername target"
183
+ selectable.getsockopt level, optname
184
+ end
185
+
186
+ # @private
187
+ def set_sock_opt signature, level, optname, optval
188
+ selectable = Reactor.instance.get_selectable( signature ) or raise "unknown get_peername target"
189
+ selectable.setsockopt level, optname, optval
190
+ end
191
+
192
+ # @private
193
+ def send_file_data sig, filename
194
+ sz = File.size(filename)
195
+ raise "file too large" if sz > 32*1024
196
+ data =
197
+ begin
198
+ File.read filename
199
+ rescue
200
+ ""
201
+ end
202
+ send_data sig, data, data.length
203
+ end
204
+
205
+ # @private
206
+ def get_outbound_data_size sig
207
+ r = Reactor.instance.get_selectable( sig ) or raise "unknown get_outbound_data_size target"
208
+ r.get_outbound_data_size
209
+ end
210
+
211
+ # @private
212
+ def read_keyboard
213
+ EvmaKeyboard.open.uuid
214
+ end
215
+
216
+ # @private
217
+ def set_comm_inactivity_timeout sig, tm
218
+ r = Reactor.instance.get_selectable( sig ) or raise "unknown set_comm_inactivity_timeout target"
219
+ r.set_inactivity_timeout tm
220
+ end
221
+ end
222
+ end
223
+
224
+
225
+ module EventMachine
226
+ # @private
227
+ class Error < Exception; end
228
+ end
229
+
230
+ module EventMachine
231
+ # @private
232
+ class Connection
233
+ # @private
234
+ def get_outbound_data_size
235
+ EventMachine::get_outbound_data_size @signature
236
+ end
237
+ end
238
+ end
239
+
240
+ module EventMachine
241
+
242
+ # Factored out so we can substitute other implementations
243
+ # here if desired, such as the one in ActiveRBAC.
244
+ # @private
245
+ module UuidGenerator
246
+ def self.generate
247
+ @ix ||= 0
248
+ @ix += 1
249
+ end
250
+ end
251
+ end
252
+
253
+
254
+ module EventMachine
255
+ # @private
256
+ TimerFired = 100
257
+ # @private
258
+ ConnectionData = 101
259
+ # @private
260
+ ConnectionUnbound = 102
261
+ # @private
262
+ ConnectionAccepted = 103
263
+ # @private
264
+ ConnectionCompleted = 104
265
+ # @private
266
+ LoopbreakSignalled = 105
267
+ end
268
+
269
+ module EventMachine
270
+ # @private
271
+ class Reactor
272
+ include Singleton
273
+
274
+ HeartbeatInterval = 2
275
+
276
+ attr_reader :current_loop_time
277
+
278
+ def initialize
279
+ initialize_for_run
280
+ end
281
+
282
+ def install_oneshot_timer interval
283
+ uuid = UuidGenerator::generate
284
+ #@timers << [Time.now + interval, uuid]
285
+ #@timers.sort! {|a,b| a.first <=> b.first}
286
+ @timers.add([Time.now + interval, uuid])
287
+ uuid
288
+ end
289
+
290
+ # Called before run, this is a good place to clear out arrays
291
+ # with cruft that may be left over from a previous run.
292
+ # @private
293
+ def initialize_for_run
294
+ @running = false
295
+ @stop_scheduled = false
296
+ @selectables ||= {}; @selectables.clear
297
+ @timers = SortedSet.new # []
298
+ set_timer_quantum(0.1)
299
+ @current_loop_time = Time.now
300
+ @next_heartbeat = @current_loop_time + HeartbeatInterval
301
+ end
302
+
303
+ def add_selectable io
304
+ @selectables[io.uuid] = io
305
+ end
306
+
307
+ def get_selectable uuid
308
+ @selectables[uuid]
309
+ end
310
+
311
+ def run
312
+ raise Error.new( "already running" ) if @running
313
+ @running = true
314
+
315
+ begin
316
+ open_loopbreaker
317
+
318
+ loop {
319
+ @current_loop_time = Time.now
320
+
321
+ break if @stop_scheduled
322
+ run_timers
323
+ break if @stop_scheduled
324
+ crank_selectables
325
+ break if @stop_scheduled
326
+ run_heartbeats
327
+ }
328
+ ensure
329
+ close_loopbreaker
330
+ @selectables.each {|k, io| io.close}
331
+ @selectables.clear
332
+
333
+ @running = false
334
+ end
335
+
336
+ end
337
+
338
+ def run_timers
339
+ @timers.each {|t|
340
+ if t.first <= @current_loop_time
341
+ @timers.delete t
342
+ EventMachine::event_callback "", TimerFired, t.last
343
+ else
344
+ break
345
+ end
346
+ }
347
+ #while @timers.length > 0 and @timers.first.first <= now
348
+ # t = @timers.shift
349
+ # EventMachine::event_callback "", TimerFired, t.last
350
+ #end
351
+ end
352
+
353
+ def run_heartbeats
354
+ if @next_heartbeat <= @current_loop_time
355
+ @next_heartbeat = @current_loop_time + HeartbeatInterval
356
+ @selectables.each {|k,io| io.heartbeat}
357
+ end
358
+ end
359
+
360
+ def crank_selectables
361
+ #$stderr.write 'R'
362
+
363
+ readers = @selectables.values.select {|io| io.select_for_reading?}
364
+ writers = @selectables.values.select {|io| io.select_for_writing?}
365
+
366
+ s = select( readers, writers, nil, @timer_quantum)
367
+
368
+ s and s[1] and s[1].each {|w| w.eventable_write }
369
+ s and s[0] and s[0].each {|r| r.eventable_read }
370
+
371
+ @selectables.delete_if {|k,io|
372
+ if io.close_scheduled?
373
+ io.close
374
+ true
375
+ end
376
+ }
377
+ end
378
+
379
+ # #stop
380
+ def stop
381
+ raise Error.new( "not running") unless @running
382
+ @stop_scheduled = true
383
+ end
384
+
385
+ def open_loopbreaker
386
+ # Can't use an IO.pipe because they can't be set nonselectable in Windows.
387
+ # Pick a random localhost UDP port.
388
+ #@loopbreak_writer.close if @loopbreak_writer
389
+ #rd,@loopbreak_writer = IO.pipe
390
+ @loopbreak_reader = UDPSocket.new
391
+ @loopbreak_writer = UDPSocket.new
392
+ bound = false
393
+ 100.times {
394
+ @loopbreak_port = rand(10000) + 40000
395
+ begin
396
+ @loopbreak_reader.bind "localhost", @loopbreak_port
397
+ bound = true
398
+ break
399
+ rescue
400
+ end
401
+ }
402
+ raise "Unable to bind Loopbreaker" unless bound
403
+ LoopbreakReader.new(@loopbreak_reader)
404
+ end
405
+
406
+ def close_loopbreaker
407
+ @loopbreak_writer.close
408
+ @loopbreak_writer = nil
409
+ end
410
+
411
+ def signal_loopbreak
412
+ #@loopbreak_writer.write '+' if @loopbreak_writer
413
+ @loopbreak_writer.send('+',0,"localhost",@loopbreak_port) if @loopbreak_writer
414
+ end
415
+
416
+ def set_timer_quantum interval_in_seconds
417
+ @timer_quantum = interval_in_seconds
418
+ end
419
+
420
+ end
421
+
422
+ end
423
+
424
+ # @private
425
+ class IO
426
+ extend Forwardable
427
+ def_delegator :@my_selectable, :close_scheduled?
428
+ def_delegator :@my_selectable, :select_for_reading?
429
+ def_delegator :@my_selectable, :select_for_writing?
430
+ def_delegator :@my_selectable, :eventable_read
431
+ def_delegator :@my_selectable, :eventable_write
432
+ def_delegator :@my_selectable, :uuid
433
+ def_delegator :@my_selectable, :send_data
434
+ def_delegator :@my_selectable, :schedule_close
435
+ def_delegator :@my_selectable, :get_peername
436
+ def_delegator :@my_selectable, :send_datagram
437
+ def_delegator :@my_selectable, :get_outbound_data_size
438
+ def_delegator :@my_selectable, :set_inactivity_timeout
439
+ def_delegator :@my_selectable, :heartbeat
440
+ end
441
+
442
+ module EventMachine
443
+ # @private
444
+ class Selectable
445
+
446
+ attr_reader :io, :uuid
447
+
448
+ def initialize io
449
+ @uuid = UuidGenerator.generate
450
+ @io = io
451
+ @last_activity = Reactor.instance.current_loop_time
452
+
453
+ if defined?(Fcntl::F_GETFL)
454
+ m = @io.fcntl(Fcntl::F_GETFL, 0)
455
+ @io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK | m)
456
+ else
457
+ # Windows doesn't define F_GETFL.
458
+ # It's not very reliable about setting descriptors nonblocking either.
459
+ begin
460
+ s = Socket.for_fd(@io.fileno)
461
+ s.fcntl( Fcntl::F_SETFL, Fcntl::O_NONBLOCK )
462
+ rescue Errno::EINVAL, Errno::EBADF
463
+ warn "Serious error: unable to set descriptor non-blocking"
464
+ end
465
+ end
466
+ # TODO, should set CLOEXEC on Unix?
467
+
468
+ @close_scheduled = false
469
+ @close_requested = false
470
+
471
+ se = self; @io.instance_eval { @my_selectable = se }
472
+ Reactor.instance.add_selectable @io
473
+ end
474
+
475
+ def close_scheduled?
476
+ @close_scheduled
477
+ end
478
+
479
+ def select_for_reading?
480
+ false
481
+ end
482
+
483
+ def select_for_writing?
484
+ false
485
+ end
486
+
487
+ def get_peername
488
+ nil
489
+ end
490
+
491
+ def set_inactivity_timeout tm
492
+ @inactivity_timeout = tm
493
+ end
494
+
495
+ def heartbeat
496
+ end
497
+ end
498
+
499
+ end
500
+
501
+ module EventMachine
502
+ # @private
503
+ class StreamObject < Selectable
504
+ def initialize io
505
+ super io
506
+ @outbound_q = []
507
+ end
508
+
509
+ # If we have to close, or a close-after-writing has been requested,
510
+ # then don't read any more data.
511
+ def select_for_reading?
512
+ true unless (@close_scheduled || @close_requested)
513
+ end
514
+
515
+ # If we have to close, don't select for writing.
516
+ # Otherwise, see if the protocol is ready to close.
517
+ # If not, see if he has data to send.
518
+ # If a close-after-writing has been requested and the outbound queue
519
+ # is empty, convert the status to close_scheduled.
520
+ def select_for_writing?
521
+ unless @close_scheduled
522
+ if @outbound_q.empty?
523
+ @close_scheduled = true if @close_requested
524
+ false
525
+ else
526
+ true
527
+ end
528
+ end
529
+ end
530
+
531
+ # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
532
+ # If we have it, then we can read multiple times safely to improve
533
+ # performance.
534
+ # The last-activity clock ASSUMES that we only come here when we
535
+ # have selected readable.
536
+ # TODO, coalesce multiple reads into a single event.
537
+ # TODO, do the function check somewhere else and cache it.
538
+ def eventable_read
539
+ @last_activity = Reactor.instance.current_loop_time
540
+ begin
541
+ if io.respond_to?(:read_nonblock)
542
+ 10.times {
543
+ data = io.read_nonblock(4096)
544
+ EventMachine::event_callback uuid, ConnectionData, data
545
+ }
546
+ else
547
+ data = io.sysread(4096)
548
+ EventMachine::event_callback uuid, ConnectionData, data
549
+ end
550
+ rescue Errno::EAGAIN, Errno::EWOULDBLOCK
551
+ # no-op
552
+ rescue Errno::ECONNRESET, Errno::ECONNREFUSED, EOFError
553
+ @close_scheduled = true
554
+ EventMachine::event_callback uuid, ConnectionUnbound, nil
555
+ end
556
+
557
+ end
558
+
559
+ # Provisional implementation. Will be re-implemented in subclasses.
560
+ # TODO: Complete this implementation. As it stands, this only writes
561
+ # a single packet per cycle. Highly inefficient, but required unless
562
+ # we're running on a Ruby with proper nonblocking I/O (Ruby 1.8.4
563
+ # built from sources from May 25, 2006 or newer).
564
+ # We need to improve the loop so it writes multiple times, however
565
+ # not more than a certain number of bytes per cycle, otherwise
566
+ # one busy connection could hog output buffers and slow down other
567
+ # connections. Also we should coalesce small writes.
568
+ # URGENT TODO: Coalesce small writes. They are a performance killer.
569
+ # The last-activity recorder ASSUMES we'll only come here if we've
570
+ # selected writable.
571
+ def eventable_write
572
+ # coalesce the outbound array here, perhaps
573
+ @last_activity = Reactor.instance.current_loop_time
574
+ while data = @outbound_q.shift do
575
+ begin
576
+ data = data.to_s
577
+ w = if io.respond_to?(:write_nonblock)
578
+ io.write_nonblock data
579
+ else
580
+ io.syswrite data
581
+ end
582
+
583
+ if w < data.length
584
+ @outbound_q.unshift data[w..-1]
585
+ break
586
+ end
587
+ rescue Errno::EAGAIN
588
+ @outbound_q.unshift data
589
+ rescue EOFError, Errno::ECONNRESET, Errno::ECONNREFUSED
590
+ @close_scheduled = true
591
+ @outbound_q.clear
592
+ end
593
+ end
594
+
595
+ end
596
+
597
+ # #send_data
598
+ def send_data data
599
+ # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
600
+ unless @close_scheduled or @close_requested or !data or data.length <= 0
601
+ @outbound_q << data.to_s
602
+ end
603
+ end
604
+
605
+ # #schedule_close
606
+ # The application wants to close the connection.
607
+ def schedule_close after_writing
608
+ if after_writing
609
+ @close_requested = true
610
+ else
611
+ @close_scheduled = true
612
+ end
613
+ end
614
+
615
+ # #get_peername
616
+ # This is defined in the normal way on connected stream objects.
617
+ # Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants.
618
+ # We could also use a convenience method that did the unpacking automatically.
619
+ def get_peername
620
+ io.getpeername
621
+ end
622
+
623
+ # #get_outbound_data_size
624
+ def get_outbound_data_size
625
+ @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
626
+ end
627
+
628
+ def heartbeat
629
+ if @inactivity_timeout and @inactivity_timeout > 0 and (@last_activity + @inactivity_timeout) < Reactor.instance.current_loop_time
630
+ schedule_close true
631
+ end
632
+ end
633
+ end
634
+
635
+
636
+ end
637
+
638
+
639
+ #--------------------------------------------------------------
640
+
641
+
642
+
643
+ module EventMachine
644
+ # @private
645
+ class EvmaTCPClient < StreamObject
646
+
647
+ def self.connect bind_addr, bind_port, host, port
648
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
649
+ sd.bind( Socket.pack_sockaddr_in( bind_port, bind_addr )) if bind_addr
650
+
651
+ begin
652
+ # TODO, this assumes a current Ruby snapshot.
653
+ # We need to degrade to a nonblocking connect otherwise.
654
+ sd.connect_nonblock( Socket.pack_sockaddr_in( port, host ))
655
+ rescue Errno::EINPROGRESS
656
+ end
657
+ EvmaTCPClient.new sd
658
+ end
659
+
660
+
661
+ def initialize io
662
+ super
663
+ @pending = true
664
+ end
665
+
666
+
667
+ def select_for_writing?
668
+ @pending ? true : super
669
+ end
670
+
671
+ def select_for_reading?
672
+ @pending ? false : super
673
+ end
674
+
675
+ def eventable_write
676
+ if @pending
677
+ @pending = false
678
+ if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
679
+ EventMachine::event_callback uuid, ConnectionCompleted, ""
680
+ end
681
+ else
682
+ super
683
+ end
684
+ end
685
+
686
+
687
+
688
+ end
689
+ end
690
+
691
+
692
+
693
+ module EventMachine
694
+ # @private
695
+ class EvmaKeyboard < StreamObject
696
+
697
+ def self.open
698
+ EvmaKeyboard.new STDIN
699
+ end
700
+
701
+
702
+ def initialize io
703
+ super
704
+ end
705
+
706
+
707
+ def select_for_writing?
708
+ false
709
+ end
710
+
711
+ def select_for_reading?
712
+ true
713
+ end
714
+
715
+
716
+ end
717
+ end
718
+
719
+
720
+
721
+ module EventMachine
722
+ # @private
723
+ class EvmaUNIXClient < StreamObject
724
+
725
+ def self.connect chain
726
+ sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
727
+ begin
728
+ # TODO, this assumes a current Ruby snapshot.
729
+ # We need to degrade to a nonblocking connect otherwise.
730
+ sd.connect_nonblock( Socket.pack_sockaddr_un( chain ))
731
+ rescue Errno::EINPROGRESS
732
+ end
733
+ EvmaUNIXClient.new sd
734
+ end
735
+
736
+
737
+ def initialize io
738
+ super
739
+ @pending = true
740
+ end
741
+
742
+
743
+ def select_for_writing?
744
+ @pending ? true : super
745
+ end
746
+
747
+ def select_for_reading?
748
+ @pending ? false : super
749
+ end
750
+
751
+ def eventable_write
752
+ if @pending
753
+ @pending = false
754
+ if 0 == io.getsockopt(Socket::SOL_SOCKET, Socket::SO_ERROR).unpack("i").first
755
+ EventMachine::event_callback uuid, ConnectionCompleted, ""
756
+ end
757
+ else
758
+ super
759
+ end
760
+ end
761
+
762
+
763
+
764
+ end
765
+ end
766
+
767
+
768
+ #--------------------------------------------------------------
769
+
770
+ module EventMachine
771
+ # @private
772
+ class EvmaTCPServer < Selectable
773
+
774
+ # TODO, refactor and unify with EvmaUNIXServer.
775
+
776
+ class << self
777
+ # Versions of ruby 1.8.4 later than May 26 2006 will work properly
778
+ # with an object of type TCPServer. Prior versions won't so we
779
+ # play it safe and just build a socket.
780
+ #
781
+ def start_server host, port
782
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
783
+ sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
784
+ sd.bind( Socket.pack_sockaddr_in( port, host ))
785
+ sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
786
+ EvmaTCPServer.new sd
787
+ end
788
+ end
789
+
790
+ def initialize io
791
+ super io
792
+ end
793
+
794
+
795
+ def select_for_reading?
796
+ true
797
+ end
798
+
799
+ #--
800
+ # accept_nonblock returns an array consisting of the accepted
801
+ # socket and a sockaddr_in which names the peer.
802
+ # Don't accept more than 10 at a time.
803
+ def eventable_read
804
+ begin
805
+ 10.times {
806
+ descriptor,peername = io.accept_nonblock
807
+ sd = StreamObject.new descriptor
808
+ EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
809
+ }
810
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
811
+ end
812
+ end
813
+
814
+ #--
815
+ #
816
+ def schedule_close
817
+ @close_scheduled = true
818
+ end
819
+
820
+ end
821
+ end
822
+
823
+
824
+ #--------------------------------------------------------------
825
+
826
+ module EventMachine
827
+ # @private
828
+ class EvmaUNIXServer < Selectable
829
+
830
+ # TODO, refactor and unify with EvmaTCPServer.
831
+
832
+ class << self
833
+ # Versions of ruby 1.8.4 later than May 26 2006 will work properly
834
+ # with an object of type TCPServer. Prior versions won't so we
835
+ # play it safe and just build a socket.
836
+ #
837
+ def start_server chain
838
+ sd = Socket.new( Socket::AF_LOCAL, Socket::SOCK_STREAM, 0 )
839
+ sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
840
+ sd.bind( Socket.pack_sockaddr_un( chain ))
841
+ sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
842
+ EvmaUNIXServer.new sd
843
+ end
844
+ end
845
+
846
+ def initialize io
847
+ super io
848
+ end
849
+
850
+
851
+ def select_for_reading?
852
+ true
853
+ end
854
+
855
+ #--
856
+ # accept_nonblock returns an array consisting of the accepted
857
+ # socket and a sockaddr_in which names the peer.
858
+ # Don't accept more than 10 at a time.
859
+ def eventable_read
860
+ begin
861
+ 10.times {
862
+ descriptor,peername = io.accept_nonblock
863
+ sd = StreamObject.new descriptor
864
+ EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
865
+ }
866
+ rescue Errno::EWOULDBLOCK, Errno::EAGAIN
867
+ end
868
+ end
869
+
870
+ #--
871
+ #
872
+ def schedule_close
873
+ @close_scheduled = true
874
+ end
875
+
876
+ end
877
+ end
878
+
879
+
880
+
881
+ #--------------------------------------------------------------
882
+
883
+ module EventMachine
884
+ # @private
885
+ class LoopbreakReader < Selectable
886
+
887
+ def select_for_reading?
888
+ true
889
+ end
890
+
891
+ def eventable_read
892
+ io.sysread(128)
893
+ EventMachine::event_callback "", LoopbreakSignalled, ""
894
+ end
895
+
896
+ end
897
+ end
898
+
899
+
900
+
901
+ # @private
902
+ module EventMachine
903
+ # @private
904
+ class DatagramObject < Selectable
905
+ def initialize io
906
+ super io
907
+ @outbound_q = []
908
+ end
909
+
910
+ # #send_datagram
911
+ def send_datagram data, target
912
+ # TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
913
+ unless @close_scheduled or @close_requested
914
+ @outbound_q << [data.to_s, target]
915
+ end
916
+ end
917
+
918
+ # #select_for_writing?
919
+ def select_for_writing?
920
+ unless @close_scheduled
921
+ if @outbound_q.empty?
922
+ @close_scheduled = true if @close_requested
923
+ false
924
+ else
925
+ true
926
+ end
927
+ end
928
+ end
929
+
930
+ # #select_for_reading?
931
+ def select_for_reading?
932
+ true
933
+ end
934
+
935
+ # #get_outbound_data_size
936
+ def get_outbound_data_size
937
+ @outbound_q.inject(0) {|memo,obj| memo += (obj || "").length}
938
+ end
939
+
940
+
941
+ end
942
+
943
+
944
+ end
945
+
946
+
947
+ module EventMachine
948
+ # @private
949
+ class EvmaUDPSocket < DatagramObject
950
+
951
+ class << self
952
+ def create host, port
953
+ sd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
954
+ sd.bind Socket::pack_sockaddr_in( port, host )
955
+ EvmaUDPSocket.new sd
956
+ end
957
+ end
958
+
959
+ # #eventable_write
960
+ # This really belongs in DatagramObject, but there is some UDP-specific stuff.
961
+ def eventable_write
962
+ 40.times {
963
+ break if @outbound_q.empty?
964
+ begin
965
+ data,target = @outbound_q.first
966
+
967
+ # This damn better be nonblocking.
968
+ io.send data.to_s, 0, target
969
+
970
+ @outbound_q.shift
971
+ rescue Errno::EAGAIN
972
+ # It's not been observed in testing that we ever get here.
973
+ # True to the definition, packets will be accepted and quietly dropped
974
+ # if the system is under pressure.
975
+ break
976
+ rescue EOFError, Errno::ECONNRESET
977
+ @close_scheduled = true
978
+ @outbound_q.clear
979
+ end
980
+ }
981
+ end
982
+
983
+ # Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
984
+ # If we have it, then we can read multiple times safely to improve
985
+ # performance.
986
+ def eventable_read
987
+ begin
988
+ if io.respond_to?(:recvfrom_nonblock)
989
+ 40.times {
990
+ data,@return_address = io.recvfrom_nonblock(16384)
991
+ EventMachine::event_callback uuid, ConnectionData, data
992
+ @return_address = nil
993
+ }
994
+ else
995
+ raise "unimplemented datagram-read operation on this Ruby"
996
+ end
997
+ rescue Errno::EAGAIN
998
+ # no-op
999
+ rescue Errno::ECONNRESET, EOFError
1000
+ @close_scheduled = true
1001
+ EventMachine::event_callback uuid, ConnectionUnbound, nil
1002
+ end
1003
+
1004
+ end
1005
+
1006
+
1007
+ def send_data data
1008
+ send_datagram data, @return_address
1009
+ end
1010
+
1011
+ end
1012
+ end
1013
+
1014
+ # load base EM api on top, now that we have the underlying pure ruby
1015
+ # implementation defined
1016
+ require 'eventmachine'
1017
+