eventmachine 0.9.0 → 0.10.0
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.
- data/DEFERRABLES +3 -3
- data/PURE_RUBY +77 -0
- data/ext/cmain.cpp +41 -2
- data/ext/ed.cpp +67 -3
- data/ext/ed.h +4 -1
- data/ext/em.cpp +33 -10
- data/ext/em.h +6 -14
- data/ext/eventmachine.h +4 -1
- data/ext/pipe.cpp +21 -3
- data/ext/rubymain.cpp +38 -1
- data/ext/ssl.cpp +9 -3
- data/lib/em/streamer.rb +1 -3
- data/lib/eventmachine.rb +190 -38
- data/lib/eventmachine_version.rb +2 -2
- data/lib/pr_eventmachine.rb +309 -28
- data/lib/protocols/httpcli2.rb +784 -0
- data/lib/protocols/saslauth.rb +121 -0
- data/lib/protocols/smtpclient.rb +41 -10
- data/lib/protocols/smtpserver.rb +30 -1
- data/tests/test_basic.rb +33 -2
- data/tests/test_epoll.rb +9 -3
- data/tests/test_errors.rb +72 -0
- data/tests/test_httpclient2.rb +132 -0
- data/tests/test_pure.rb +127 -0
- data/tests/test_timers.rb +30 -1
- metadata +37 -32
- data/ext/eee +0 -173
- data/lib/svn-commit.tmp +0 -4
@@ -0,0 +1,121 @@
|
|
1
|
+
# $Id: saslauth.rb 568 2007-11-13 02:36:17Z blackhedd $
|
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
|
+
|
28
|
+
|
29
|
+
module EventMachine
|
30
|
+
module Protocols
|
31
|
+
|
32
|
+
# Implements SASL authd.
|
33
|
+
# This is a very, very simple protocol that mimics the one used
|
34
|
+
# by saslauthd and pwcheck, two outboard daemons included in the
|
35
|
+
# standard SASL library distro.
|
36
|
+
# The only thing this is really suitable for is SASL PLAIN
|
37
|
+
# (user+password) authentication, but the SASL libs that are
|
38
|
+
# linked into standard servers (like imapd and sendmail) implement
|
39
|
+
# the other ones.
|
40
|
+
#
|
41
|
+
# SASL-auth is intended for reasonably fast operation inside a
|
42
|
+
# single machine, so it has no transport-security (although there
|
43
|
+
# have been multi-machine extensions incorporating transport-layer
|
44
|
+
# encryption).
|
45
|
+
#
|
46
|
+
# The standard saslauthd module generally runs privileged and does
|
47
|
+
# its work by referring to the system-account files.
|
48
|
+
#
|
49
|
+
# This feature was added to EventMachine to enable the development
|
50
|
+
# of custom authentication/authorization engines for standard servers.
|
51
|
+
#
|
52
|
+
# To use SASLauth, include it in a class that subclasses EM::Connection,
|
53
|
+
# and reimplement the validate method.
|
54
|
+
#
|
55
|
+
# The typical way to incorporate this module into an authentication
|
56
|
+
# daemon would be to set it as the handler for a UNIX-domain socket.
|
57
|
+
# The code might look like this:
|
58
|
+
#
|
59
|
+
# EM.start_unix_domain_server( "/var/run/saslauthd/mux", MyHandler )
|
60
|
+
# File.chmod( 0777, "/var/run/saslauthd/mux")
|
61
|
+
#
|
62
|
+
# The chmod is probably needed to ensure that unprivileged clients can
|
63
|
+
# access the UNIX-domain socket.
|
64
|
+
#
|
65
|
+
# It's also a very good idea to drop superuser privileges (if any), after
|
66
|
+
# the UNIX-domain socket has been opened.
|
67
|
+
#--
|
68
|
+
# Implementation details: assume the client can send us pipelined requests,
|
69
|
+
# and that the client will close the connection.
|
70
|
+
#
|
71
|
+
# The client sends us four values, each encoded as a two-byte length field in
|
72
|
+
# network order followed by the specified number of octets.
|
73
|
+
# The fields specify the username, password, service name (such as imap),
|
74
|
+
# and the "realm" name. We send back the barest minimum reply, a single
|
75
|
+
# field also encoded as a two-octet length in network order, followed by
|
76
|
+
# either "NO" or "OK" - simplicity itself.
|
77
|
+
#
|
78
|
+
# We enforce a maximum field size just as a sanity check.
|
79
|
+
# We do NOT automatically time out the connection.
|
80
|
+
#
|
81
|
+
# The code we use to parse out the values is ugly and probably slow.
|
82
|
+
# Improvements welcome.
|
83
|
+
#
|
84
|
+
module SASLauth
|
85
|
+
|
86
|
+
MaxFieldSize = 128*1024
|
87
|
+
def post_init
|
88
|
+
super
|
89
|
+
@sasl_data = ""
|
90
|
+
@sasl_values = []
|
91
|
+
end
|
92
|
+
|
93
|
+
def receive_data data
|
94
|
+
@sasl_data << data
|
95
|
+
while @sasl_data.length >= 2
|
96
|
+
len = (@sasl_data[0,2].unpack("n")).first
|
97
|
+
raise "SASL Max Field Length exceeded" if len > MaxFieldSize
|
98
|
+
if @sasl_data.length >= (len + 2)
|
99
|
+
@sasl_values << @sasl_data[2,len]
|
100
|
+
@sasl_data.slice!(0...(2+len))
|
101
|
+
if @sasl_values.length == 4
|
102
|
+
send_data( validate(*@sasl_values) ? "\0\002OK" : "\0\002NO" )
|
103
|
+
@sasl_values.clear
|
104
|
+
end
|
105
|
+
else
|
106
|
+
break
|
107
|
+
end
|
108
|
+
end
|
109
|
+
end
|
110
|
+
def validate username, psw, sysname, realm
|
111
|
+
p username
|
112
|
+
p psw
|
113
|
+
p sysname
|
114
|
+
p realm
|
115
|
+
true
|
116
|
+
end
|
117
|
+
end
|
118
|
+
end
|
119
|
+
end
|
120
|
+
|
121
|
+
|
data/lib/protocols/smtpclient.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: smtpclient.rb
|
1
|
+
# $Id: smtpclient.rb 549 2007-09-22 00:49:42Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -25,6 +25,7 @@
|
|
25
25
|
|
26
26
|
|
27
27
|
require 'base64'
|
28
|
+
require 'ostruct'
|
28
29
|
|
29
30
|
module EventMachine
|
30
31
|
module Protocols
|
@@ -78,6 +79,11 @@ module Protocols
|
|
78
79
|
def self.send args={}
|
79
80
|
args[:port] ||= 25
|
80
81
|
args[:body] ||= ""
|
82
|
+
|
83
|
+
=begin
|
84
|
+
(I don't think it's possible for EM#connect to throw an exception under normal
|
85
|
+
circumstances, so this original code is stubbed out. A connect-failure will result
|
86
|
+
in the #unbind method being called without calling #connection_completed.)
|
81
87
|
begin
|
82
88
|
EventMachine.connect( args[:host], args[:port], self) {|c|
|
83
89
|
# According to the EM docs, we will get here AFTER post_init is called.
|
@@ -93,13 +99,20 @@ module Protocols
|
|
93
99
|
d.set_deferred_status(:failed, {:error=>[:connect, 500, "unable to connect to server"]})
|
94
100
|
d
|
95
101
|
end
|
102
|
+
=end
|
103
|
+
EventMachine.connect( args[:host], args[:port], self) {|c|
|
104
|
+
# According to the EM docs, we will get here AFTER post_init is called.
|
105
|
+
c.args = args
|
106
|
+
c.set_comm_inactivity_timeout 60
|
107
|
+
}
|
108
|
+
|
96
109
|
end
|
97
110
|
|
98
111
|
attr_writer :args
|
99
112
|
|
100
113
|
def post_init
|
101
|
-
@return_values =
|
102
|
-
@return_values
|
114
|
+
@return_values = OpenStruct.new
|
115
|
+
@return_values.start_time = Time.now
|
103
116
|
end
|
104
117
|
|
105
118
|
def connection_completed
|
@@ -114,8 +127,10 @@ module Protocols
|
|
114
127
|
#
|
115
128
|
def unbind
|
116
129
|
unless @succeeded
|
117
|
-
@return_values
|
118
|
-
@return_values
|
130
|
+
@return_values.elapsed_time = Time.now - @return_values.start_time
|
131
|
+
@return_values.responder = @responder
|
132
|
+
@return_values.code = @code
|
133
|
+
@return_values.message = @msg
|
119
134
|
set_deferred_status(:failed, @return_values)
|
120
135
|
end
|
121
136
|
end
|
@@ -136,7 +151,11 @@ module Protocols
|
|
136
151
|
# Use the error and message the server returned.
|
137
152
|
#
|
138
153
|
def invoke_error
|
139
|
-
|
154
|
+
@return_values.elapsed_time = Time.now - @return_values.start_time
|
155
|
+
@return_values.responder = @responder
|
156
|
+
@return_values.code = @code
|
157
|
+
@return_values.message = @msg
|
158
|
+
set_deferred_status :failed, @return_values
|
140
159
|
send_data "QUIT\r\n"
|
141
160
|
close_connection_after_writing
|
142
161
|
end
|
@@ -145,7 +164,11 @@ module Protocols
|
|
145
164
|
# Use an extra-protocol error code (900) and use the message from the caller.
|
146
165
|
#
|
147
166
|
def invoke_internal_error msg = "???"
|
148
|
-
|
167
|
+
@return_values.elapsed_time = Time.now - @return_values.start_time
|
168
|
+
@return_values.responder = @responder
|
169
|
+
@return_values.code = 900
|
170
|
+
@return_values.message = msg
|
171
|
+
set_deferred_status :failed, @return_values
|
149
172
|
send_data "QUIT\r\n"
|
150
173
|
close_connection_after_writing
|
151
174
|
end
|
@@ -221,11 +244,16 @@ module Protocols
|
|
221
244
|
send_data "RCPT TO: <#{to[l]}>\r\n"
|
222
245
|
@responder = :receive_rcpt_to_response
|
223
246
|
else
|
224
|
-
|
247
|
+
e = @rcpt_responses.select {|rr| rr.last == 2}
|
248
|
+
if e and e.length > 0
|
249
|
+
invoke_data
|
250
|
+
else
|
251
|
+
invoke_error
|
252
|
+
end
|
225
253
|
end
|
226
254
|
end
|
227
255
|
def receive_rcpt_to_response
|
228
|
-
@rcpt_responses << [@code, @msg]
|
256
|
+
@rcpt_responses << [@code, @msg, @range]
|
229
257
|
invoke_rcpt_to
|
230
258
|
end
|
231
259
|
|
@@ -267,7 +295,10 @@ module Protocols
|
|
267
295
|
send_data "QUIT\r\n"
|
268
296
|
close_connection_after_writing
|
269
297
|
@succeeded = true
|
270
|
-
@return_values
|
298
|
+
@return_values.elapsed_time = Time.now - @return_values.start_time
|
299
|
+
@return_values.responder = @responder
|
300
|
+
@return_values.code = @code
|
301
|
+
@return_values.message = @msg
|
271
302
|
set_deferred_status :succeeded, @return_values
|
272
303
|
end
|
273
304
|
end
|
data/lib/protocols/smtpserver.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: smtpserver.rb
|
1
|
+
# $Id: smtpserver.rb 545 2007-09-19 21:07:28Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -299,6 +299,7 @@ module Protocols
|
|
299
299
|
|
300
300
|
def process_rset
|
301
301
|
reset_protocol_state
|
302
|
+
receive_reset
|
302
303
|
send_data "250 Ok\r\n"
|
303
304
|
end
|
304
305
|
|
@@ -365,16 +366,37 @@ module Protocols
|
|
365
366
|
# We might want to make sure that a given recipient is only seen once, but
|
366
367
|
# for now we'll let that be the user's problem.
|
367
368
|
#
|
369
|
+
# User-written code can return a deferrable from receive_recipient.
|
370
|
+
#
|
368
371
|
def process_rcpt_to rcpt
|
369
372
|
unless @state.include?(:mail_from)
|
370
373
|
send_data "503 MAIL is required before RCPT\r\n"
|
371
374
|
else
|
375
|
+
succeeded = proc {
|
376
|
+
send_data "250 Ok\r\n"
|
377
|
+
@state << :rcpt unless @state.include?(:rcpt)
|
378
|
+
}
|
379
|
+
failed = proc {
|
380
|
+
send_data "550 recipient is unacceptable\r\n"
|
381
|
+
}
|
382
|
+
|
383
|
+
d = receive_recipient rcpt
|
384
|
+
|
385
|
+
if d.respond_to?(:set_deferred_status)
|
386
|
+
d.callback &succeeded
|
387
|
+
d.errback &failed
|
388
|
+
else
|
389
|
+
(d ? succeeded : failed).call
|
390
|
+
end
|
391
|
+
|
392
|
+
=begin
|
372
393
|
unless receive_recipient rcpt
|
373
394
|
send_data "550 recipient is unacceptable\r\n"
|
374
395
|
else
|
375
396
|
send_data "250 Ok\r\n"
|
376
397
|
@state << :rcpt unless @state.include?(:rcpt)
|
377
398
|
end
|
399
|
+
=end
|
378
400
|
end
|
379
401
|
end
|
380
402
|
|
@@ -470,6 +492,13 @@ module Protocols
|
|
470
492
|
true
|
471
493
|
end
|
472
494
|
|
495
|
+
# Sent when the remote peer issues the RSET command.
|
496
|
+
# Since RSET is not allowed to fail (according to the protocol),
|
497
|
+
# we ignore any return value from user overrides of this method.
|
498
|
+
#
|
499
|
+
def receive_reset
|
500
|
+
end
|
501
|
+
|
473
502
|
# Sent when the remote peer has ended the connection.
|
474
503
|
#
|
475
504
|
def connection_ended
|
data/tests/test_basic.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_basic.rb
|
1
|
+
# $Id: test_basic.rb 607 2007-12-09 20:59:12Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -39,7 +39,7 @@ class TestBasic < Test::Unit::TestCase
|
|
39
39
|
|
40
40
|
def test_libtype
|
41
41
|
lt = EventMachine.library_type
|
42
|
-
case $eventmachine_library
|
42
|
+
case (ENV["EVENTMACHINE_LIBRARY"] || $eventmachine_library || :xxx).to_sym
|
43
43
|
when :pure_ruby
|
44
44
|
assert_equal( :pure_ruby, lt )
|
45
45
|
when :extension
|
@@ -105,6 +105,37 @@ class TestBasic < Test::Unit::TestCase
|
|
105
105
|
|
106
106
|
#--------------------------------------
|
107
107
|
|
108
|
+
# TODO! This is an unfinished edge case.
|
109
|
+
# EM mishandles uncaught Ruby exceptions that fire from within #unbind handlers.
|
110
|
+
# A uncaught Ruby exception results in a call to EM::release_machine (which is in an ensure
|
111
|
+
# block in EM::run). But if EM is processing an unbind request, the release_machine call
|
112
|
+
# will cause a segmentation fault.
|
113
|
+
#
|
114
|
+
|
115
|
+
TestHost = "127.0.0.1"
|
116
|
+
TestPort = 9070
|
117
|
+
|
118
|
+
class UnbindError < EM::Connection
|
119
|
+
def initialize *args
|
120
|
+
super
|
121
|
+
end
|
122
|
+
def connection_completed
|
123
|
+
close_connection_after_writing
|
124
|
+
end
|
125
|
+
def unbind
|
126
|
+
raise "Blooey"
|
127
|
+
end
|
128
|
+
end
|
129
|
+
|
130
|
+
def xxx_test_unbind_error
|
131
|
+
assert_raise( RuntimeError ) {
|
132
|
+
EM.run {
|
133
|
+
EM.start_server TestHost, TestPort
|
134
|
+
EM.connect TestHost, TestPort, UnbindError
|
135
|
+
}
|
136
|
+
}
|
137
|
+
end
|
138
|
+
|
108
139
|
end
|
109
140
|
|
110
141
|
|
data/tests/test_epoll.rb
CHANGED
@@ -1,4 +1,4 @@
|
|
1
|
-
# $Id: test_epoll.rb
|
1
|
+
# $Id: test_epoll.rb 599 2007-12-05 14:24:11Z blackhedd $
|
2
2
|
#
|
3
3
|
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
4
|
# Homepage:: http://rubyeventmachine.com
|
@@ -143,15 +143,21 @@ class TestEpoll < Test::Unit::TestCase
|
|
143
143
|
EM.epoll
|
144
144
|
s = EM.set_descriptor_table_size 60000
|
145
145
|
EM.run {
|
146
|
+
# The pure-Ruby version won't let us open the socket if the node already exists.
|
147
|
+
# Not sure, that actually may be correct and the compiled version is wrong.
|
148
|
+
# Pure Ruby also oddly won't let us make that many connections. This test used
|
149
|
+
# to run 100 times. Not sure where that lower connection-limit is coming from in
|
150
|
+
# pure Ruby.
|
151
|
+
File.unlink("./xxx.chain")
|
146
152
|
EM.start_unix_domain_server "./xxx.chain", TestEchoServer
|
147
153
|
$n = 0
|
148
154
|
$max = 0
|
149
|
-
|
155
|
+
50.times {
|
150
156
|
EM.connect_unix_domain("./xxx.chain", TestEchoClient) {$n += 1}
|
151
157
|
}
|
152
158
|
}
|
153
159
|
assert_equal(0, $n)
|
154
|
-
assert_equal(
|
160
|
+
assert_equal(50, $max)
|
155
161
|
end
|
156
162
|
|
157
163
|
end
|
@@ -0,0 +1,72 @@
|
|
1
|
+
# $Id: test_errors.rb 557 2007-10-03 07:21:02Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: Francis Cianfrocca (gmail: blackhedd)
|
4
|
+
# Homepage:: http://rubyeventmachine.com
|
5
|
+
# Date:: 8 April 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
|
+
$:.unshift "../lib"
|
28
|
+
require 'eventmachine'
|
29
|
+
|
30
|
+
class TestErrors < Test::Unit::TestCase
|
31
|
+
|
32
|
+
Localhost = "127.0.0.1"
|
33
|
+
Localport = 9801
|
34
|
+
|
35
|
+
def setup
|
36
|
+
end
|
37
|
+
|
38
|
+
def teardown
|
39
|
+
# Calling #set_runtime_error_hook with no block restores the
|
40
|
+
# default handling of runtime_errors.
|
41
|
+
#
|
42
|
+
EM.set_runtime_error_hook
|
43
|
+
end
|
44
|
+
|
45
|
+
# EM has a default handler for RuntimeErrors that are emitted from
|
46
|
+
# user written code. You can override the handler if you wish, but it's
|
47
|
+
# easier to call #set_runtime_error_hook.
|
48
|
+
# Ordinarily, an error in user code invoked by the reactor aborts the
|
49
|
+
# run.
|
50
|
+
#
|
51
|
+
def test_unhandled_error
|
52
|
+
assert_raise( RuntimeError ) {
|
53
|
+
EM.run {
|
54
|
+
EM.add_timer(0) {raise "AAA"}
|
55
|
+
}
|
56
|
+
}
|
57
|
+
|
58
|
+
end
|
59
|
+
|
60
|
+
def test_handled_error
|
61
|
+
err = nil
|
62
|
+
EM.run {
|
63
|
+
EM.set_runtime_error_hook {
|
64
|
+
err = true
|
65
|
+
EM.stop
|
66
|
+
}
|
67
|
+
EM.add_timer(0) {raise "AAA"}
|
68
|
+
}
|
69
|
+
assert err
|
70
|
+
end
|
71
|
+
end
|
72
|
+
|