eventmachine 0.12.8 → 0.12.10

Sign up to get free protection for your applications and to get access to all the features.
Files changed (66) hide show
  1. data/.gitignore +2 -1
  2. data/Rakefile +155 -45
  3. data/eventmachine.gemspec +4 -5
  4. data/ext/binder.cpp +13 -14
  5. data/ext/binder.h +5 -7
  6. data/ext/cmain.cpp +184 -42
  7. data/ext/cplusplus.cpp +20 -20
  8. data/ext/ed.cpp +242 -81
  9. data/ext/ed.h +39 -22
  10. data/ext/em.cpp +127 -108
  11. data/ext/em.h +27 -18
  12. data/ext/emwin.cpp +3 -3
  13. data/ext/eventmachine.h +49 -38
  14. data/ext/eventmachine_cpp.h +4 -4
  15. data/ext/extconf.rb +28 -13
  16. data/ext/fastfilereader/extconf.rb +11 -5
  17. data/ext/project.h +12 -1
  18. data/ext/rubymain.cpp +222 -103
  19. data/ext/ssl.cpp +3 -3
  20. data/ext/ssl.h +2 -2
  21. data/java/src/com/rubyeventmachine/EmReactor.java +396 -249
  22. data/java/src/com/rubyeventmachine/EventableChannel.java +16 -4
  23. data/java/src/com/rubyeventmachine/EventableDatagramChannel.java +23 -5
  24. data/java/src/com/rubyeventmachine/EventableSocketChannel.java +181 -61
  25. data/java/src/com/rubyeventmachine/{Application.java → application/Application.java} +25 -31
  26. data/java/src/com/rubyeventmachine/{Connection.java → application/Connection.java} +2 -2
  27. data/java/src/com/rubyeventmachine/{ConnectionFactory.java → application/ConnectionFactory.java} +1 -1
  28. data/java/src/com/rubyeventmachine/{DefaultConnectionFactory.java → application/DefaultConnectionFactory.java} +2 -2
  29. data/java/src/com/rubyeventmachine/{PeriodicTimer.java → application/PeriodicTimer.java} +1 -1
  30. data/java/src/com/rubyeventmachine/{Timer.java → application/Timer.java} +1 -1
  31. data/java/src/com/rubyeventmachine/tests/ApplicationTest.java +1 -0
  32. data/java/src/com/rubyeventmachine/tests/ConnectTest.java +4 -2
  33. data/java/src/com/rubyeventmachine/tests/TestDatagrams.java +1 -1
  34. data/java/src/com/rubyeventmachine/tests/TestServers.java +1 -0
  35. data/java/src/com/rubyeventmachine/tests/TestTimers.java +1 -0
  36. data/lib/em/connection.rb +71 -12
  37. data/lib/em/deferrable.rb +5 -0
  38. data/lib/em/protocols.rb +1 -0
  39. data/lib/em/protocols/httpclient2.rb +8 -0
  40. data/lib/em/protocols/line_and_text.rb +0 -1
  41. data/lib/em/protocols/linetext2.rb +1 -0
  42. data/lib/em/protocols/object_protocol.rb +8 -2
  43. data/lib/em/protocols/smtpclient.rb +42 -16
  44. data/lib/em/protocols/socks4.rb +66 -0
  45. data/lib/em/queue.rb +1 -1
  46. data/lib/em/timers.rb +2 -1
  47. data/lib/em/version.rb +1 -1
  48. data/lib/eventmachine.rb +125 -169
  49. data/lib/jeventmachine.rb +124 -9
  50. data/tasks/{cpp.rake → cpp.rake_example} +0 -0
  51. data/tests/test_attach.rb +29 -4
  52. data/tests/test_basic.rb +1 -2
  53. data/tests/test_connection_count.rb +10 -20
  54. data/tests/test_epoll.rb +0 -2
  55. data/tests/test_get_sock_opt.rb +30 -0
  56. data/tests/test_httpclient2.rb +3 -3
  57. data/tests/test_inactivity_timeout.rb +21 -1
  58. data/tests/test_ltp.rb +0 -6
  59. data/tests/test_next_tick.rb +0 -2
  60. data/tests/test_pause.rb +70 -0
  61. data/tests/test_pending_connect_timeout.rb +48 -0
  62. data/tests/test_ssl_args.rb +16 -5
  63. data/tests/test_timers.rb +22 -1
  64. metadata +14 -12
  65. data/tasks/project.rake +0 -79
  66. data/tasks/tests.rake +0 -193
@@ -29,6 +29,32 @@
29
29
 
30
30
  require 'java'
31
31
  require 'em_reactor'
32
+ require 'socket'
33
+
34
+ java_import java.io.FileDescriptor
35
+ java_import java.nio.channels.SocketChannel
36
+ java_import java.lang.reflect.Field
37
+
38
+ module JavaFields
39
+ def set_field(key, value)
40
+ field = getClass.getDeclaredField(key)
41
+ field.setAccessible(true)
42
+ if field.getType.toString == 'int'
43
+ field.setInt(self, value)
44
+ else
45
+ field.set(self, value)
46
+ end
47
+ end
48
+
49
+ def get_field(key)
50
+ field = getClass.getDeclaredField(key)
51
+ field.setAccessible(true)
52
+ field.get(self)
53
+ end
54
+ end
55
+
56
+ FileDescriptor.send :include, JavaFields
57
+ SocketChannel.send :include, JavaFields
32
58
 
33
59
  module EventMachine
34
60
  # TODO: These event numbers are defined in way too many places.
@@ -39,20 +65,29 @@ module EventMachine
39
65
  ConnectionAccepted = 103
40
66
  ConnectionCompleted = 104
41
67
  LoopbreakSignalled = 105
68
+ ConnectionNotifyReadable = 106
69
+ ConnectionNotifyWritable = 107
70
+ SslHandshakeCompleted = 108
71
+
72
+ # Exceptions that are defined in rubymain.cpp
73
+ class ConnectionNotBound < RuntimeError; end
74
+ class UnknownTimerFired < RuntimeError; end
75
+ class Unsupported < RuntimeError; end
42
76
 
43
77
  # This thunk class used to be called EM, but that caused conflicts with
44
78
  # the alias "EM" for module EventMachine. (FC, 20Jun08)
45
79
  class JEM < com.rubyeventmachine.EmReactor
46
- def eventCallback a1, a2, a3
47
- s = String.from_java_bytes(a3.array[a3.position...a3.limit])
48
- EventMachine::event_callback a1, a2, s
49
- end
50
- end
51
- class Connection < com.rubyeventmachine.Connection
52
- def associate_callback_target sig
53
- # No-op for the time being.
80
+ def eventCallback a1, a2, a3, a4
81
+ s = String.from_java_bytes(a3.array[a3.position...a3.limit]) if a3
82
+ EventMachine::event_callback a1, a2, s || a4
83
+ nil
54
84
  end
55
85
  end
86
+ # class Connection < com.rubyeventmachine.Connection
87
+ # def associate_callback_target sig
88
+ # # No-op for the time being.
89
+ # end
90
+ # end
56
91
  def self.initialize_event_machine
57
92
  @em = JEM.new
58
93
  end
@@ -88,7 +123,7 @@ module EventMachine
88
123
  bind_connect_server nil, nil, server, port
89
124
  end
90
125
  def self.bind_connect_server bind_addr, bind_port, server, port
91
- @em.connectTcpServer bind_addr, bind_port, server, port
126
+ @em.connectTcpServer bind_addr, bind_port.to_i, server, port
92
127
  end
93
128
  def self.close_connection sig, after_writing
94
129
  @em.closeConnection sig, after_writing
@@ -112,6 +147,18 @@ module EventMachine
112
147
  # Epoll is a no-op for Java.
113
148
  # The latest Java versions run epoll when possible in NIO.
114
149
  end
150
+ def self.epoll= val
151
+ end
152
+ def self.kqueue
153
+ end
154
+ def self.kqueue= val
155
+ end
156
+ def self.epoll?
157
+ false
158
+ end
159
+ def self.kqueue?
160
+ false
161
+ end
115
162
  def self.set_rlimit_nofile n_descriptors
116
163
  # Currently a no-op for Java.
117
164
  end
@@ -128,10 +175,78 @@ module EventMachine
128
175
  end
129
176
  def self.set_max_timer_count num
130
177
  # harmless no-op in Java. There's no built-in timer limit.
178
+ @max_timer_count = num
179
+ end
180
+ def self.get_max_timer_count
181
+ # harmless no-op in Java. There's no built-in timer limit.
182
+ @max_timer_count || 100_000
131
183
  end
132
184
  def self.library_type
133
185
  :java
134
186
  end
187
+ def self.get_peername sig
188
+ if peer = @em.getPeerName(sig)
189
+ Socket.pack_sockaddr_in *peer
190
+ end
191
+ end
192
+ def self.attach_fd fileno, watch_mode
193
+ # 3Aug09: We could pass in the actual SocketChannel, but then it would be modified (set as non-blocking), and
194
+ # we would need some logic to make sure detach_fd below didn't clobber it. For now, we just always make a new
195
+ # SocketChannel for the underlying file descriptor
196
+ # if fileno.java_kind_of? SocketChannel
197
+ # ch = fileno
198
+ # ch.configureBlocking(false)
199
+ # fileno = nil
200
+ # elsif fileno.java_kind_of? java.nio.channels.Channel
201
+
202
+ if fileno.java_kind_of? java.nio.channels.Channel
203
+ field = fileno.getClass.getDeclaredField('fdVal')
204
+ field.setAccessible(true)
205
+ fileno = field.get(fileno)
206
+ else
207
+ raise ArgumentError, 'attach_fd requires Java Channel or POSIX fileno' unless fileno.is_a? Fixnum
208
+ end
209
+
210
+ if fileno == 0
211
+ raise "can't open STDIN as selectable in Java =("
212
+ elsif fileno.is_a? Fixnum
213
+ # 8Aug09: The following code is specific to the sun jvm's SocketChannelImpl. Is there a cross-platform
214
+ # way of implementing this? If so, also remember to update EventableSocketChannel#close and #cleanup
215
+ fd = FileDescriptor.new
216
+ fd.set_field 'fd', fileno
217
+
218
+ ch = SocketChannel.open
219
+ ch.configureBlocking(false)
220
+ ch.kill
221
+ ch.set_field 'fd', fd
222
+ ch.set_field 'fdVal', fileno
223
+ ch.set_field 'state', ch.get_field('ST_CONNECTED')
224
+ end
225
+
226
+ @em.attachChannel(ch,watch_mode)
227
+ end
228
+ def self.detach_fd sig
229
+ if ch = @em.detachChannel(sig)
230
+ ch.get_field 'fdVal'
231
+ end
232
+ end
233
+
234
+ def self.set_notify_readable sig, mode
235
+ @em.setNotifyReadable(sig, mode)
236
+ end
237
+ def self.set_notify_writable sig, mode
238
+ @em.setNotifyWritable(sig, mode)
239
+ end
240
+
241
+ def self.is_notify_readable sig
242
+ @em.isNotifyReadable(sig)
243
+ end
244
+ def self.is_notify_writable sig
245
+ @em.isNotifyWritable(sig)
246
+ end
247
+ def self.get_connection_count
248
+ @em.getConnectionCount
249
+ end
135
250
 
136
251
  class Connection
137
252
  def associate_callback_target sig
File without changes
@@ -34,6 +34,7 @@ class TestAttach < Test::Unit::TestCase
34
34
 
35
35
  class EchoClient < EM::Connection
36
36
  def initialize
37
+ self.notify_readable = true
37
38
  $sock.write("abc\n")
38
39
  end
39
40
 
@@ -54,16 +55,17 @@ class TestAttach < Test::Unit::TestCase
54
55
  EM.run{
55
56
  EM.start_server Host, Port, EchoServer
56
57
  $sock = TCPSocket.new Host, Port
57
- EM.attach $sock, EchoClient
58
+ EM.watch $sock, EchoClient
58
59
  }
59
60
 
60
61
  assert_equal $read, "abc\n"
61
- assert_equal $fd, $sock.fileno
62
+ unless defined? JRuby # jruby filenos are not real
63
+ assert_equal $fd, $sock.fileno
64
+ end
62
65
  assert_equal false, $sock.closed?
63
66
  assert_equal $sock.readline, "def\n"
64
67
  end
65
68
 
66
-
67
69
  module PipeWatch
68
70
  def notify_readable
69
71
  $read = $r.readline
@@ -74,13 +76,36 @@ class TestAttach < Test::Unit::TestCase
74
76
  def test_attach_pipe
75
77
  EM.run{
76
78
  $r, $w = IO.pipe
77
- EM.attach $r, PipeWatch
79
+ EM.watch $r, PipeWatch do |c|
80
+ c.notify_readable = true
81
+ end
78
82
  $w.write("ghi\n")
79
83
  }
80
84
 
81
85
  assert_equal $read, "ghi\n"
82
86
  end
83
87
 
88
+ def test_set_readable
89
+ EM.run{
90
+ $r, $w = IO.pipe
91
+ c = EM.watch $r, PipeWatch do |c|
92
+ c.notify_readable = false
93
+ end
94
+
95
+ EM.next_tick{
96
+ $before = c.notify_readable?
97
+ c.notify_readable = true
98
+ $after = c.notify_readable?
99
+ }
100
+
101
+ $w.write("jkl\n")
102
+ }
103
+
104
+ assert !$before
105
+ assert $after
106
+ assert_equal $read, "jkl\n"
107
+ end
108
+
84
109
  module PipeReader
85
110
  def receive_data data
86
111
  $read = data
@@ -266,8 +266,7 @@ class TestBasic < Test::Unit::TestCase
266
266
  x = false
267
267
  assert !x
268
268
  EM.run do
269
- Thread.new { EM.schedule { x = true } }.join
270
- EM.stop
269
+ Thread.new { EM.schedule { x = true; EM.stop } }.join
271
270
  end
272
271
  assert x
273
272
  end
@@ -14,32 +14,22 @@ class TestConnectionCount < Test::Unit::TestCase
14
14
 
15
15
  module Client
16
16
  def connection_completed
17
- EM.next_tick{
18
- $client_connected = EM.connection_count
19
- EM.stop
20
- }
21
- end
22
- end
23
-
24
- module Server
25
- def post_init
26
- $server_connected = EM.connection_count
17
+ $client_conns += 1
18
+ EM.stop if $client_conns == 3
27
19
  end
28
20
  end
29
21
 
30
22
  def test_with_some_connections
31
23
  EM.run {
32
- $initial = EM.connection_count
33
- EM.start_server("127.0.0.1", 9999, Server)
34
- $server_started = EM.connection_count
35
- EM.next_tick{
36
- EM.connect("127.0.0.1", 9999, Client)
37
- }
24
+ $client_conns = 0
25
+ $initial_conns = EM.connection_count
26
+ EM.start_server("127.0.0.1", 9999)
27
+ $server_conns = EM.connection_count
28
+ 3.times { EM.connect("127.0.0.1", 9999, Client) }
38
29
  }
39
30
 
40
- assert_equal(0, $initial)
41
- assert_equal(1, $server_started)
42
- assert_equal(2, $server_connected)
43
- assert_equal(3, $client_connected)
31
+ assert_equal(0, $initial_conns)
32
+ assert_equal(1, $server_conns)
33
+ assert_equal(4, $client_conns + $server_conns)
44
34
  end
45
35
  end
@@ -94,7 +94,6 @@ class TestEpoll < Test::Unit::TestCase
94
94
  n = 0
95
95
  work_proc = proc {n += 1}
96
96
  callback_proc = proc {EM.stop}
97
- EM.epoll
98
97
  EM.run {
99
98
  EM.defer work_proc, callback_proc
100
99
  }
@@ -120,7 +119,6 @@ class TestEpoll < Test::Unit::TestCase
120
119
 
121
120
  def test_datagrams
122
121
  $in = $out = ""
123
- EM.epoll
124
122
  EM.run {
125
123
  EM.open_datagram_socket "127.0.0.1", 9500, TestDatagramServer
126
124
  EM.open_datagram_socket "127.0.0.1", 0, TestDatagramClient
@@ -0,0 +1,30 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
2
+ require 'eventmachine'
3
+ require 'socket'
4
+ require 'test/unit'
5
+
6
+ class TestGetSockOpt < Test::Unit::TestCase
7
+
8
+ def setup
9
+ assert(!EM.reactor_running?)
10
+ end
11
+
12
+ def teardown
13
+ assert(!EM.reactor_running?)
14
+ end
15
+
16
+ #-------------------------------------
17
+
18
+ def test_get_sock_opt
19
+ test = self
20
+ EM.run do
21
+ EM.connect 'google.com', 80, Module.new {
22
+ define_method :connection_completed do
23
+ val = get_sock_opt Socket::SOL_SOCKET, Socket::SO_ERROR
24
+ test.assert_equal "\0\0\0\0", val
25
+ EM.stop
26
+ end
27
+ }
28
+ end
29
+ end
30
+ end
@@ -80,7 +80,7 @@ class TestHttpClient2 < Test::Unit::TestCase
80
80
  def test_get
81
81
  content = nil
82
82
  EM.run {
83
- http = EM::P::HttpClient2.connect "www.bayshorenetworks.com", 80
83
+ http = EM::P::HttpClient2.connect "google.com", 80
84
84
  d = http.get "/"
85
85
  d.callback {
86
86
  content = d.content
@@ -96,7 +96,7 @@ class TestHttpClient2 < Test::Unit::TestCase
96
96
  def _test_get_multiple
97
97
  content = nil
98
98
  EM.run {
99
- http = EM::P::HttpClient2.connect "www.bayshorenetworks.com", 80
99
+ http = EM::P::HttpClient2.connect "google.com", 80
100
100
  d = http.get "/"
101
101
  d.callback {
102
102
  e = http.get "/"
@@ -112,7 +112,7 @@ class TestHttpClient2 < Test::Unit::TestCase
112
112
  def test_get_pipeline
113
113
  headers, headers2 = nil, nil
114
114
  EM.run {
115
- http = EM::P::HttpClient2.connect "www.microsoft.com", 80
115
+ http = EM::P::HttpClient2.connect "google.com", 80
116
116
  d = http.get("/")
117
117
  d.callback {
118
118
  headers = d.headers
@@ -15,7 +15,7 @@ class TestInactivityTimeout < Test::Unit::TestCase
15
15
  assert_equal(0.0, $timeout)
16
16
  end
17
17
 
18
- def test_with_set
18
+ def test_set_and_get
19
19
  $timeout = nil
20
20
  EM.run {
21
21
  c = EM.connect("127.0.0.1", 54321)
@@ -27,4 +27,24 @@ class TestInactivityTimeout < Test::Unit::TestCase
27
27
  assert_equal(2.5, $timeout)
28
28
  end
29
29
 
30
+ module TimeoutHandler
31
+ def unbind
32
+ EM.stop
33
+ end
34
+ end
35
+
36
+ def test_for_real
37
+ EM.run {
38
+ EM.heartbeat_interval = 0.1
39
+ EM.start_server("127.0.0.1", 12345)
40
+ EM.add_timer(0.2) {
41
+ $start = Time.now
42
+ c = EM.connect("127.0.0.1", 12345, TimeoutHandler)
43
+ c.comm_inactivity_timeout = 2.5
44
+ }
45
+ }
46
+
47
+ assert_in_delta(2.5, (Time.now - $start), 0.3)
48
+ end
49
+
30
50
  end
@@ -58,9 +58,6 @@ class TestLineAndTextProtocol < Test::Unit::TestCase
58
58
 
59
59
 
60
60
  def test_simple_lines
61
- # THIS TEST CURRENTLY FAILS IN JRUBY.
62
- assert( RUBY_PLATFORM !~ /java/ )
63
-
64
61
  lines_received = []
65
62
  EventMachine.run {
66
63
  EventMachine.start_server( TestHost, TestPort, SimpleLineTest ) do |conn|
@@ -85,9 +82,6 @@ class TestLineAndTextProtocol < Test::Unit::TestCase
85
82
  end
86
83
 
87
84
  def test_overlength_lines
88
- # THIS TEST CURRENTLY FAILS IN JRUBY.
89
- assert( RUBY_PLATFORM !~ /java/ )
90
-
91
85
  lines_received = []
92
86
  EventMachine.run {
93
87
  EventMachine.start_server( TestHost, TestPort, SimpleLineTest ) do |conn|
@@ -33,7 +33,6 @@ class TestNextTick < Test::Unit::TestCase
33
33
 
34
34
  def test_tick_arg
35
35
  pr = proc {EM.stop}
36
- EM.epoll
37
36
  EM.run {
38
37
  EM.next_tick pr
39
38
  }
@@ -41,7 +40,6 @@ class TestNextTick < Test::Unit::TestCase
41
40
  end
42
41
 
43
42
  def test_tick_block
44
- EM.epoll
45
43
  EM.run {
46
44
  EM.next_tick {EM.stop}
47
45
  }
@@ -0,0 +1,70 @@
1
+ $:.unshift File.expand_path(File.dirname(__FILE__) + "/../lib")
2
+ require 'eventmachine'
3
+ require 'socket'
4
+ require 'test/unit'
5
+
6
+ class TestPause < Test::Unit::TestCase
7
+ TestHost = "127.0.0.1"
8
+ TestPort = 9070
9
+
10
+ def setup
11
+ assert(!EM.reactor_running?)
12
+ end
13
+
14
+ def teardown
15
+ assert(!EM.reactor_running?)
16
+ end
17
+
18
+ #-------------------------------------
19
+
20
+ def test_pause_resume
21
+ test = self
22
+ server = nil
23
+
24
+ s_rx = c_rx = 0
25
+
26
+ EM.run do
27
+ EM.start_server TestHost, TestPort, Module.new {
28
+ define_method :post_init do
29
+ server = self
30
+ end
31
+
32
+ define_method :receive_data do |data|
33
+ s_rx += 1
34
+
35
+ EM.add_periodic_timer(0.01) { send_data 'hi' }
36
+ send_data 'hi'
37
+
38
+ # pause server, now no outgoing data will actually
39
+ # be sent and no more incoming data will be received
40
+ pause
41
+ end
42
+ }
43
+
44
+ c = EM.connect TestHost, TestPort, Module.new {
45
+ define_method :receive_data do |data|
46
+ c_rx += 1
47
+ end
48
+ }
49
+ EM.add_periodic_timer(0.01) { c.send_data 'hi' }
50
+
51
+ EM.add_timer(1) do
52
+ test.assert_equal 1, s_rx
53
+ test.assert_equal 0, c_rx
54
+ test.assert server.paused?
55
+
56
+ # resume server, queued outgoing and incoming data will be flushed
57
+ server.resume
58
+
59
+ test.assert ! server.paused?
60
+
61
+ EM.add_timer(1) do
62
+ test.assert server.paused?
63
+ test.assert s_rx >= 2
64
+ test.assert c_rx >= 1
65
+ EM.stop_event_loop
66
+ end
67
+ end
68
+ end
69
+ end
70
+ end