eventmachine-win32 0.5.3 → 0.7.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/RELEASE_NOTES +14 -1
- data/TODO +10 -0
- data/lib/em/deferrable.rb +89 -0
- data/lib/em/eventable.rb +50 -0
- data/lib/eventmachine.rb +274 -9
- data/lib/eventmachine_version.rb +42 -0
- data/lib/evma.rb +35 -0
- data/lib/evma/callback.rb +35 -0
- data/lib/evma/container.rb +77 -0
- data/lib/evma/factory.rb +80 -0
- data/lib/evma/protocol.rb +89 -0
- data/lib/evma/reactor.rb +50 -0
- data/lib/pr_eventmachine.rb +714 -0
- data/lib/protocols/header_and_content.rb +134 -0
- data/lib/protocols/httpclient.rb +233 -0
- data/lib/protocols/line_and_text.rb +141 -0
- data/lib/protocols/tcptest.rb +67 -0
- data/lib/rubyeventmachine.so +0 -0
- data/tests/test_basic.rb +106 -0
- data/tests/test_eventables.rb +85 -0
- data/tests/test_hc.rb +207 -0
- data/tests/test_httpclient.rb +94 -0
- data/tests/test_ltp.rb +192 -0
- data/tests/test_ud.rb +52 -0
- metadata +29 -3
@@ -0,0 +1,42 @@
|
|
1
|
+
# $Id: eventmachine_version.rb 221 2006-08-07 13:17:51Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: blackhedd (gmail address: garbagecat10).
|
4
|
+
# Date:: 8 Apr 2006
|
5
|
+
#
|
6
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
7
|
+
#
|
8
|
+
# This program is made available under the terms of the GPL version 2.
|
9
|
+
#
|
10
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
11
|
+
# usage examples.
|
12
|
+
#
|
13
|
+
#----------------------------------------------------------------------------
|
14
|
+
#
|
15
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
16
|
+
#
|
17
|
+
# Gmail: garbagecat10
|
18
|
+
#
|
19
|
+
# This program is free software; you can redistribute it and/or modify
|
20
|
+
# it under the terms of the GNU General Public License as published by
|
21
|
+
# the Free Software Foundation; either version 2 of the License, or
|
22
|
+
# (at your option) any later version.
|
23
|
+
#
|
24
|
+
# This program is distributed in the hope that it will be useful,
|
25
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27
|
+
# GNU General Public License for more details.
|
28
|
+
#
|
29
|
+
# You should have received a copy of the GNU General Public License
|
30
|
+
# along with this program; if not, write to the Free Software
|
31
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
32
|
+
#
|
33
|
+
#---------------------------------------------------------------------------
|
34
|
+
#
|
35
|
+
#
|
36
|
+
|
37
|
+
module EventMachine
|
38
|
+
|
39
|
+
VERSION = "0.7.0"
|
40
|
+
|
41
|
+
end
|
42
|
+
|
data/lib/evma.rb
ADDED
@@ -0,0 +1,35 @@
|
|
1
|
+
# $Id: evma.rb 88 2006-05-19 03:42:54Z blackhedd $
|
2
|
+
#
|
3
|
+
# Homepage:: http://rubyeventmachine.com
|
4
|
+
# Copyright:: (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
5
|
+
# Email:: gmail address: garbagecat10
|
6
|
+
#
|
7
|
+
# Available under the GNU Lesser General Public License.
|
8
|
+
# See the file COPYING in the distribution for full licensing information.
|
9
|
+
#-------------------------------------------------------------------
|
10
|
+
# This file is part of Ruby/EventMachine.
|
11
|
+
#
|
12
|
+
# Ruby/EventMachine is free software; you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
14
|
+
# the Free Software Foundation; either version 2.1 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
#
|
17
|
+
# Ruby/EventMachine is distributed in the hope that it will be useful,
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
+
# GNU Lesser General Public License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Lesser General Public License
|
23
|
+
# along with Ruby/EventMachine; if not, write to the Free Software
|
24
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
25
|
+
#-------------------------------------------------------------------
|
26
|
+
#
|
27
|
+
|
28
|
+
|
29
|
+
require 'rubyeventmachine'
|
30
|
+
require 'evma/reactor'
|
31
|
+
require 'evma/callback'
|
32
|
+
require 'evma/protocol'
|
33
|
+
require 'evma/factory'
|
34
|
+
require 'evma/container'
|
35
|
+
|
@@ -0,0 +1,35 @@
|
|
1
|
+
# $Id: callback.rb 88 2006-05-19 03:42:54Z blackhedd $
|
2
|
+
#
|
3
|
+
# Homepage:: http://rubyeventmachine.com
|
4
|
+
# Copyright:: (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
5
|
+
# Email:: gmail address: garbagecat10
|
6
|
+
#
|
7
|
+
# Available under the GNU Lesser General Public License.
|
8
|
+
# See the file COPYING in the distribution for full licensing information.
|
9
|
+
#-------------------------------------------------------------------
|
10
|
+
# This file is part of Ruby/EventMachine.
|
11
|
+
#
|
12
|
+
# Ruby/EventMachine is free software; you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
14
|
+
# the Free Software Foundation; either version 2.1 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
#
|
17
|
+
# Ruby/EventMachine is distributed in the hope that it will be useful,
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
+
# GNU Lesser General Public License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Lesser General Public License
|
23
|
+
# along with Ruby/EventMachine; if not, write to the Free Software
|
24
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
25
|
+
#-------------------------------------------------------------------
|
26
|
+
#
|
27
|
+
|
28
|
+
|
29
|
+
module EventMachine
|
30
|
+
|
31
|
+
def self.event_callback target, opcode, data
|
32
|
+
Evma::Container.callback target, opcode, data
|
33
|
+
end
|
34
|
+
|
35
|
+
end # module EventMachine
|
@@ -0,0 +1,77 @@
|
|
1
|
+
# $Id: container.rb 90 2006-05-19 04:58:15Z blackhedd $
|
2
|
+
#
|
3
|
+
# Homepage:: http://rubyeventmachine.com
|
4
|
+
# Copyright:: (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
5
|
+
# Email:: gmail address: garbagecat10
|
6
|
+
#
|
7
|
+
# Available under the GNU Lesser General Public License.
|
8
|
+
# See the file COPYING in the distribution for full licensing information.
|
9
|
+
#-------------------------------------------------------------------
|
10
|
+
# This file is part of Ruby/EventMachine.
|
11
|
+
#
|
12
|
+
# Ruby/EventMachine is free software; you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
14
|
+
# the Free Software Foundation; either version 2.1 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
#
|
17
|
+
# Ruby/EventMachine is distributed in the hope that it will be useful,
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
+
# GNU Lesser General Public License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Lesser General Public License
|
23
|
+
# along with Ruby/EventMachine; if not, write to the Free Software
|
24
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
25
|
+
#-------------------------------------------------------------------
|
26
|
+
#
|
27
|
+
|
28
|
+
|
29
|
+
require 'singleton'
|
30
|
+
|
31
|
+
module Evma
|
32
|
+
|
33
|
+
class ContainerHasObject < Exception; end
|
34
|
+
class UnsupportedCallback < Exception; end
|
35
|
+
class UnknownTarget < Exception; end
|
36
|
+
|
37
|
+
class Container
|
38
|
+
include Singleton
|
39
|
+
|
40
|
+
def initialize
|
41
|
+
@objects = {}
|
42
|
+
end
|
43
|
+
|
44
|
+
def self.store obj
|
45
|
+
instance.store obj
|
46
|
+
end
|
47
|
+
|
48
|
+
def self.callback target, opcode, data
|
49
|
+
instance.callback target, opcode, data
|
50
|
+
end
|
51
|
+
|
52
|
+
def store obj
|
53
|
+
sig = obj.signature
|
54
|
+
raise ContainerHasObject.new(sig) if @objects.has_key?(sig)
|
55
|
+
@objects[sig] = obj
|
56
|
+
end
|
57
|
+
|
58
|
+
def callback target, opcode, data
|
59
|
+
case opcode
|
60
|
+
when 101 # received data
|
61
|
+
obj = @objects[target] or raise UnknownTarget.new( target )
|
62
|
+
obj.receive_data data
|
63
|
+
when 102 # unbind
|
64
|
+
obj = @objects[target] or raise UnknownTarget.new( target )
|
65
|
+
obj.unbind
|
66
|
+
@objects.delete obj.signature
|
67
|
+
when 103 # accept
|
68
|
+
obj = @objects[target] or raise UnknownTarget.new( target )
|
69
|
+
obj.accept data
|
70
|
+
else
|
71
|
+
raise UnsupportedCallback.new( opcode.to_s )
|
72
|
+
end
|
73
|
+
end
|
74
|
+
|
75
|
+
end # class Container
|
76
|
+
end # module Evma
|
77
|
+
|
data/lib/evma/factory.rb
ADDED
@@ -0,0 +1,80 @@
|
|
1
|
+
# $Id: factory.rb 90 2006-05-19 04:58:15Z blackhedd $
|
2
|
+
#
|
3
|
+
# Homepage:: http://rubyeventmachine.com
|
4
|
+
# Copyright:: (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
5
|
+
# Email:: gmail address: garbagecat10
|
6
|
+
#
|
7
|
+
# Available under the GNU Lesser General Public License.
|
8
|
+
# See the file COPYING in the distribution for full licensing information.
|
9
|
+
#-------------------------------------------------------------------
|
10
|
+
# This file is part of Ruby/EventMachine.
|
11
|
+
#
|
12
|
+
# Ruby/EventMachine is free software; you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
14
|
+
# the Free Software Foundation; either version 2.1 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
#
|
17
|
+
# Ruby/EventMachine is distributed in the hope that it will be useful,
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
+
# GNU Lesser General Public License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Lesser General Public License
|
23
|
+
# along with Ruby/EventMachine; if not, write to the Free Software
|
24
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
25
|
+
#-------------------------------------------------------------------
|
26
|
+
#
|
27
|
+
|
28
|
+
|
29
|
+
module Evma
|
30
|
+
class ProtocolFactory < Protocol
|
31
|
+
|
32
|
+
#--
|
33
|
+
# default implementation raises an exception.
|
34
|
+
# we expect subclasses to override this.
|
35
|
+
# we can't do anything reasonable here because
|
36
|
+
def accept new_object
|
37
|
+
# don't bother calling Evma::Reactor.instance, since only Reactor can call accept
|
38
|
+
Evma::Container.store Evma::Protocol.new( new_object )
|
39
|
+
EventMachine.close_connection new_object, false
|
40
|
+
end
|
41
|
+
|
42
|
+
|
43
|
+
end # class ProtocolFactory
|
44
|
+
end # module Evma
|
45
|
+
|
46
|
+
######################################
|
47
|
+
|
48
|
+
module Evma
|
49
|
+
class TcpSocket
|
50
|
+
|
51
|
+
def self.connect server, port, protocol_handler = Evma::Protocol
|
52
|
+
Evma::Reactor.instance # ensure initialization
|
53
|
+
sig = EventMachine.connect_server server, port
|
54
|
+
Evma::Container.store protocol_handler.new( sig )
|
55
|
+
end
|
56
|
+
|
57
|
+
end
|
58
|
+
end # module Evma
|
59
|
+
|
60
|
+
######################################
|
61
|
+
|
62
|
+
module Evma
|
63
|
+
class TcpServerFactory < Evma::ProtocolFactory
|
64
|
+
|
65
|
+
def initialize server, port, protocol_handler = Evma::Protocol
|
66
|
+
Evma::Reactor.instance # ensure initialization
|
67
|
+
sig = EventMachine.start_tcp_server server, port
|
68
|
+
super sig
|
69
|
+
@protocol_handler = protocol_handler
|
70
|
+
Evma::Container.store self
|
71
|
+
end
|
72
|
+
|
73
|
+
def accept new_obj
|
74
|
+
# don't bother calling Evma::Reactor.instance, since only Reactor can call accept
|
75
|
+
Evma::Container.store @protocol_handler.new( new_obj )
|
76
|
+
end
|
77
|
+
|
78
|
+
end
|
79
|
+
end # module Evma
|
80
|
+
|
@@ -0,0 +1,89 @@
|
|
1
|
+
# $Id: protocol.rb 90 2006-05-19 04:58:15Z blackhedd $
|
2
|
+
#
|
3
|
+
# Homepage:: http://rubyeventmachine.com
|
4
|
+
# Copyright:: (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
5
|
+
# Email:: gmail address: garbagecat10
|
6
|
+
#
|
7
|
+
# Available under the GNU Lesser General Public License.
|
8
|
+
# See the file COPYING in the distribution for full licensing information.
|
9
|
+
#-------------------------------------------------------------------
|
10
|
+
# This file is part of Ruby/EventMachine.
|
11
|
+
#
|
12
|
+
# Ruby/EventMachine is free software; you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
14
|
+
# the Free Software Foundation; either version 2.1 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
#
|
17
|
+
# Ruby/EventMachine is distributed in the hope that it will be useful,
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
+
# GNU Lesser General Public License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Lesser General Public License
|
23
|
+
# along with Ruby/EventMachine; if not, write to the Free Software
|
24
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
25
|
+
#-------------------------------------------------------------------
|
26
|
+
#
|
27
|
+
|
28
|
+
module Evma
|
29
|
+
class Protocol
|
30
|
+
|
31
|
+
attr_reader :signature
|
32
|
+
|
33
|
+
def initialize sig
|
34
|
+
@signature = sig
|
35
|
+
end
|
36
|
+
|
37
|
+
def unbind
|
38
|
+
end
|
39
|
+
|
40
|
+
def close
|
41
|
+
Evma::Reactor.instance # ensure initialized
|
42
|
+
EventMachine.close_connection signature, false
|
43
|
+
end
|
44
|
+
|
45
|
+
def close_after_writing
|
46
|
+
Evma::Reactor.instance # ensure initialized
|
47
|
+
EventMachine.close_connection signature, true
|
48
|
+
end
|
49
|
+
|
50
|
+
end # class Protocol
|
51
|
+
end # module Evma
|
52
|
+
|
53
|
+
|
54
|
+
###########################################
|
55
|
+
|
56
|
+
module Evma
|
57
|
+
class StreamProtocol < Protocol
|
58
|
+
|
59
|
+
def initialize sig
|
60
|
+
super
|
61
|
+
end
|
62
|
+
|
63
|
+
def send_data data
|
64
|
+
Evma::Reactor.instance # ensure initialized
|
65
|
+
EventMachine.send_data signature, data, data.length
|
66
|
+
end
|
67
|
+
|
68
|
+
end # class Protocol
|
69
|
+
end # module Evma
|
70
|
+
|
71
|
+
|
72
|
+
###########################################
|
73
|
+
|
74
|
+
module Evma
|
75
|
+
class DatagramProtocol < Protocol
|
76
|
+
|
77
|
+
def initialize sig
|
78
|
+
super
|
79
|
+
end
|
80
|
+
|
81
|
+
def send_message data
|
82
|
+
Evma::Reactor.instance # ensure initialized
|
83
|
+
raise "unimplemented"
|
84
|
+
end
|
85
|
+
|
86
|
+
end # class Protocol
|
87
|
+
end # module Evma
|
88
|
+
|
89
|
+
|
data/lib/evma/reactor.rb
ADDED
@@ -0,0 +1,50 @@
|
|
1
|
+
# $Id: reactor.rb 83 2006-05-18 21:36:31Z blackhedd $
|
2
|
+
#
|
3
|
+
# Homepage:: http://rubyeventmachine.com
|
4
|
+
# Copyright:: (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
5
|
+
# Email:: gmail address: garbagecat10
|
6
|
+
#
|
7
|
+
# Available under the GNU Lesser General Public License.
|
8
|
+
# See the file COPYING in the distribution for full licensing information.
|
9
|
+
#-------------------------------------------------------------------
|
10
|
+
# This file is part of Ruby/EventMachine.
|
11
|
+
#
|
12
|
+
# Ruby/EventMachine is free software; you can redistribute it and/or modify
|
13
|
+
# it under the terms of the GNU Lesser General Public License as published by
|
14
|
+
# the Free Software Foundation; either version 2.1 of the License, or
|
15
|
+
# (at your option) any later version.
|
16
|
+
#
|
17
|
+
# Ruby/EventMachine is distributed in the hope that it will be useful,
|
18
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
19
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
20
|
+
# GNU Lesser General Public License for more details.
|
21
|
+
#
|
22
|
+
# You should have received a copy of the GNU Lesser General Public License
|
23
|
+
# along with Ruby/EventMachine; if not, write to the Free Software
|
24
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
25
|
+
#-------------------------------------------------------------------
|
26
|
+
#
|
27
|
+
|
28
|
+
|
29
|
+
require 'singleton'
|
30
|
+
|
31
|
+
module Evma
|
32
|
+
class Reactor
|
33
|
+
include Singleton
|
34
|
+
|
35
|
+
#--
|
36
|
+
def initialize
|
37
|
+
EventMachine.initialize_event_machine
|
38
|
+
end
|
39
|
+
|
40
|
+
#--
|
41
|
+
#
|
42
|
+
def run
|
43
|
+
EventMachine.run_machine
|
44
|
+
end
|
45
|
+
|
46
|
+
end # class Reactor
|
47
|
+
end # module Evma
|
48
|
+
|
49
|
+
|
50
|
+
|
@@ -0,0 +1,714 @@
|
|
1
|
+
# $Id: pr_eventmachine.rb 264 2006-10-05 16:33:22Z blackhedd $
|
2
|
+
#
|
3
|
+
# Author:: blackhedd (gmail address: garbagecat10).
|
4
|
+
# Date:: 8 Apr 2006
|
5
|
+
#
|
6
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
7
|
+
#
|
8
|
+
# This program is made available under the terms of the GPL version 2.
|
9
|
+
#
|
10
|
+
# See EventMachine and EventMachine::Connection for documentation and
|
11
|
+
# usage examples.
|
12
|
+
#
|
13
|
+
#----------------------------------------------------------------------------
|
14
|
+
#
|
15
|
+
# Copyright (C) 2006 by Francis Cianfrocca. All Rights Reserved.
|
16
|
+
#
|
17
|
+
# Gmail: garbagecat10
|
18
|
+
#
|
19
|
+
# This program is free software; you can redistribute it and/or modify
|
20
|
+
# it under the terms of the GNU General Public License as published by
|
21
|
+
# the Free Software Foundation; either version 2 of the License, or
|
22
|
+
# (at your option) any later version.
|
23
|
+
#
|
24
|
+
# This program is distributed in the hope that it will be useful,
|
25
|
+
# but WITHOUT ANY WARRANTY; without even the implied warranty of
|
26
|
+
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the
|
27
|
+
# GNU General Public License for more details.
|
28
|
+
#
|
29
|
+
# You should have received a copy of the GNU General Public License
|
30
|
+
# along with this program; if not, write to the Free Software
|
31
|
+
# Foundation, Inc., 51 Franklin St, Fifth Floor, Boston, MA 02110-1301 USA
|
32
|
+
#
|
33
|
+
#---------------------------------------------------------------------------
|
34
|
+
#
|
35
|
+
#
|
36
|
+
|
37
|
+
# TODO List:
|
38
|
+
# TCP-connects currently assume non-blocking connect is available- need to
|
39
|
+
# degrade automatically on versions of Ruby prior to June 2006.
|
40
|
+
#
|
41
|
+
|
42
|
+
require 'singleton'
|
43
|
+
require 'forwardable'
|
44
|
+
require 'socket'
|
45
|
+
require 'fcntl'
|
46
|
+
|
47
|
+
|
48
|
+
module EventMachine
|
49
|
+
|
50
|
+
|
51
|
+
class << self
|
52
|
+
# This is mostly useful for automated tests.
|
53
|
+
# Return a distinctive symbol so the caller knows whether he's dealing
|
54
|
+
# with an extension or with a pure-Ruby library.
|
55
|
+
def library_type
|
56
|
+
:pure_ruby
|
57
|
+
end
|
58
|
+
|
59
|
+
# #initialize_event_machine
|
60
|
+
def initialize_event_machine
|
61
|
+
Reactor.instance.initialize_for_run
|
62
|
+
end
|
63
|
+
|
64
|
+
# #add_oneshot_timer
|
65
|
+
#--
|
66
|
+
# Changed 04Oct06: intervals from the caller are now in milliseconds, but our native-ruby
|
67
|
+
# processor still wants them in seconds.
|
68
|
+
def add_oneshot_timer interval
|
69
|
+
Reactor.instance.install_oneshot_timer(interval / 1000)
|
70
|
+
end
|
71
|
+
|
72
|
+
# run_machine
|
73
|
+
def run_machine
|
74
|
+
Reactor.instance.run
|
75
|
+
end
|
76
|
+
|
77
|
+
# release_machine. Probably a no-op.
|
78
|
+
def release_machine
|
79
|
+
end
|
80
|
+
|
81
|
+
# #stop
|
82
|
+
def stop
|
83
|
+
Reactor.instance.stop
|
84
|
+
end
|
85
|
+
|
86
|
+
# #connect_server. Return a connection descriptor to the caller.
|
87
|
+
# TODO, what do we return here if we can't connect?
|
88
|
+
def connect_server host, port
|
89
|
+
EvmaTCPClient.connect(host, port).uuid
|
90
|
+
end
|
91
|
+
|
92
|
+
# #send_data
|
93
|
+
def send_data target, data, datalength
|
94
|
+
selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
|
95
|
+
selectable.send_data data
|
96
|
+
end
|
97
|
+
|
98
|
+
# #close_connection
|
99
|
+
# The extension version does NOT raise any kind of an error if an attempt is made
|
100
|
+
# to close a non-existent connection. Not sure whether we should. For now, we'll
|
101
|
+
# raise an error here in that case.
|
102
|
+
def close_connection target, after_writing
|
103
|
+
selectable = Reactor.instance.get_selectable( target ) or raise "unknown close_connection target"
|
104
|
+
selectable.schedule_close after_writing
|
105
|
+
end
|
106
|
+
|
107
|
+
# #start_tcp_server
|
108
|
+
def start_tcp_server host, port
|
109
|
+
(s = EvmaTCPServer.start_server host, port) or raise "no acceptor"
|
110
|
+
s.uuid
|
111
|
+
end
|
112
|
+
|
113
|
+
# #signal_loopbreak
|
114
|
+
def signal_loopbreak
|
115
|
+
Reactor.instance.signal_loopbreak
|
116
|
+
end
|
117
|
+
|
118
|
+
# #get_peername
|
119
|
+
def get_peername sig
|
120
|
+
selectable = Reactor.instance.get_selectable( sig ) or raise "unknown get_peername target"
|
121
|
+
selectable.get_peername
|
122
|
+
end
|
123
|
+
|
124
|
+
# #open_udp_socket
|
125
|
+
def open_udp_socket host, port
|
126
|
+
EvmaUDPSocket.create(host, port).uuid
|
127
|
+
end
|
128
|
+
|
129
|
+
# #send_datagram. This is currently only for UDP!
|
130
|
+
# We need to make it work with unix-domain sockets as well.
|
131
|
+
def send_datagram target, data, datalength, host, port
|
132
|
+
selectable = Reactor.instance.get_selectable( target ) or raise "unknown send_data target"
|
133
|
+
selectable.send_datagram data, Socket::pack_sockaddr_in(port, host)
|
134
|
+
end
|
135
|
+
|
136
|
+
|
137
|
+
# #set_timer_quantum in milliseconds. The underlying Reactor function wants a (possibly
|
138
|
+
# fractional) number of seconds.
|
139
|
+
def set_timer_quantum interval
|
140
|
+
Reactor.instance.set_timer_quantum(( 1.0 * interval) / 1000.0)
|
141
|
+
end
|
142
|
+
|
143
|
+
end
|
144
|
+
|
145
|
+
end
|
146
|
+
|
147
|
+
|
148
|
+
#-----------------------------------------------------------------
|
149
|
+
|
150
|
+
module EventMachine
|
151
|
+
|
152
|
+
class Error < Exception; end
|
153
|
+
|
154
|
+
end
|
155
|
+
|
156
|
+
#-----------------------------------------------------------------
|
157
|
+
|
158
|
+
module EventMachine
|
159
|
+
|
160
|
+
# Factored out so we can substitute other implementations
|
161
|
+
# here if desired, such as the one in ActiveRBAC.
|
162
|
+
module UuidGenerator
|
163
|
+
|
164
|
+
def self.generate
|
165
|
+
if @ix and @ix >= 10000
|
166
|
+
@ix = nil
|
167
|
+
@seed = nil
|
168
|
+
end
|
169
|
+
|
170
|
+
@seed ||= `uuidgen`.chomp.gsub(/-/,"")
|
171
|
+
@ix ||= 0
|
172
|
+
|
173
|
+
"#{@seed}#{@ix += 1}"
|
174
|
+
end
|
175
|
+
|
176
|
+
end
|
177
|
+
|
178
|
+
end
|
179
|
+
|
180
|
+
#-----------------------------------------------------------------
|
181
|
+
|
182
|
+
module EventMachine
|
183
|
+
|
184
|
+
TimerFired = 100
|
185
|
+
ConnectionData = 101
|
186
|
+
ConnectionUnbound = 102
|
187
|
+
ConnectionAccepted = 103
|
188
|
+
ConnectionCompleted = 104
|
189
|
+
LoopbreakSignalled = 105
|
190
|
+
|
191
|
+
end
|
192
|
+
|
193
|
+
#-----------------------------------------------------------------
|
194
|
+
|
195
|
+
module EventMachine
|
196
|
+
class Reactor
|
197
|
+
include Singleton
|
198
|
+
|
199
|
+
def initialize
|
200
|
+
initialize_for_run
|
201
|
+
end
|
202
|
+
|
203
|
+
def install_oneshot_timer interval
|
204
|
+
uuid = UuidGenerator::generate
|
205
|
+
@timers << [Time.now + interval, uuid]
|
206
|
+
@timers.sort! {|a,b| a.first <=> b.first}
|
207
|
+
uuid
|
208
|
+
end
|
209
|
+
|
210
|
+
# Called before run, this is a good place to clear out arrays
|
211
|
+
# with cruft that may be left over from a previous run.
|
212
|
+
def initialize_for_run
|
213
|
+
@running = false
|
214
|
+
@stop_scheduled = false
|
215
|
+
@selectables ||= {}; @selectables.clear
|
216
|
+
@timers = []
|
217
|
+
set_timer_quantum(0.5)
|
218
|
+
end
|
219
|
+
|
220
|
+
def add_selectable io
|
221
|
+
@selectables[io.uuid] = io
|
222
|
+
end
|
223
|
+
|
224
|
+
def get_selectable uuid
|
225
|
+
@selectables[uuid]
|
226
|
+
end
|
227
|
+
|
228
|
+
def run
|
229
|
+
raise Error.new( "already running" ) if @running
|
230
|
+
@running = true
|
231
|
+
open_loopbreaker
|
232
|
+
|
233
|
+
loop {
|
234
|
+
break if @stop_scheduled
|
235
|
+
run_timers
|
236
|
+
break if @stop_scheduled
|
237
|
+
crank_selectables
|
238
|
+
}
|
239
|
+
|
240
|
+
close_loopbreaker
|
241
|
+
@selectables.each {|k, io| io.close}
|
242
|
+
@selectables.clear
|
243
|
+
|
244
|
+
@running = false
|
245
|
+
end
|
246
|
+
|
247
|
+
def run_timers
|
248
|
+
now = Time.now
|
249
|
+
while @timers.length > 0 and @timers.first.first <= now
|
250
|
+
t = @timers.shift
|
251
|
+
EventMachine::event_callback "", TimerFired, t.last
|
252
|
+
end
|
253
|
+
end
|
254
|
+
|
255
|
+
def crank_selectables
|
256
|
+
#$stderr.write 'R'
|
257
|
+
|
258
|
+
readers = @selectables.values.select {|io| io.select_for_reading?}
|
259
|
+
writers = @selectables.values.select {|io| io.select_for_writing?}
|
260
|
+
|
261
|
+
s = select( readers, writers, nil, @timer_quantum)
|
262
|
+
|
263
|
+
s and s[1] and s[1].each {|w| w.eventable_write }
|
264
|
+
s and s[0] and s[0].each {|r| r.eventable_read }
|
265
|
+
|
266
|
+
@selectables.delete_if {|k,io|
|
267
|
+
if io.close_scheduled?
|
268
|
+
io.close
|
269
|
+
true
|
270
|
+
end
|
271
|
+
}
|
272
|
+
end
|
273
|
+
|
274
|
+
# #stop
|
275
|
+
def stop
|
276
|
+
raise Error.new( "not running") unless @running
|
277
|
+
@stop_scheduled = true
|
278
|
+
end
|
279
|
+
|
280
|
+
def open_loopbreaker
|
281
|
+
@loopbreak_writer.close if @loopbreak_writer
|
282
|
+
rd,@loopbreak_writer = IO.pipe
|
283
|
+
LoopbreakReader.new rd
|
284
|
+
end
|
285
|
+
|
286
|
+
def close_loopbreaker
|
287
|
+
@loopbreak_writer.close
|
288
|
+
@loopbreak_writer = nil
|
289
|
+
end
|
290
|
+
|
291
|
+
def signal_loopbreak
|
292
|
+
@loopbreak_writer.write '+' if @loopbreak_writer
|
293
|
+
end
|
294
|
+
|
295
|
+
def set_timer_quantum interval_in_seconds
|
296
|
+
@timer_quantum = interval_in_seconds
|
297
|
+
end
|
298
|
+
|
299
|
+
end
|
300
|
+
|
301
|
+
end
|
302
|
+
|
303
|
+
|
304
|
+
#--------------------------------------------------------------
|
305
|
+
|
306
|
+
class IO
|
307
|
+
extend Forwardable
|
308
|
+
def_delegator :@my_selectable, :close_scheduled?
|
309
|
+
def_delegator :@my_selectable, :select_for_reading?
|
310
|
+
def_delegator :@my_selectable, :select_for_writing?
|
311
|
+
def_delegator :@my_selectable, :eventable_read
|
312
|
+
def_delegator :@my_selectable, :eventable_write
|
313
|
+
def_delegator :@my_selectable, :uuid
|
314
|
+
def_delegator :@my_selectable, :send_data
|
315
|
+
def_delegator :@my_selectable, :schedule_close
|
316
|
+
def_delegator :@my_selectable, :get_peername
|
317
|
+
def_delegator :@my_selectable, :send_datagram
|
318
|
+
end
|
319
|
+
|
320
|
+
#--------------------------------------------------------------
|
321
|
+
|
322
|
+
module EventMachine
|
323
|
+
class Selectable
|
324
|
+
|
325
|
+
attr_reader :io, :uuid
|
326
|
+
|
327
|
+
def initialize io
|
328
|
+
@uuid = UuidGenerator.generate
|
329
|
+
@io = io
|
330
|
+
|
331
|
+
m = @io.fcntl(Fcntl::F_GETFL, 0)
|
332
|
+
@io.fcntl(Fcntl::F_SETFL, Fcntl::O_NONBLOCK | m)
|
333
|
+
# TODO, should set CLOEXEC on Unix?
|
334
|
+
|
335
|
+
@close_scheduled = false
|
336
|
+
@close_requested = false
|
337
|
+
|
338
|
+
se = self; @io.instance_eval { @my_selectable = se }
|
339
|
+
Reactor.instance.add_selectable @io
|
340
|
+
end
|
341
|
+
|
342
|
+
def close_scheduled?
|
343
|
+
@close_scheduled
|
344
|
+
end
|
345
|
+
|
346
|
+
def select_for_reading?
|
347
|
+
false
|
348
|
+
end
|
349
|
+
|
350
|
+
def select_for_writing?
|
351
|
+
false
|
352
|
+
end
|
353
|
+
|
354
|
+
def get_peername
|
355
|
+
nil
|
356
|
+
end
|
357
|
+
|
358
|
+
end
|
359
|
+
|
360
|
+
end
|
361
|
+
|
362
|
+
#--------------------------------------------------------------
|
363
|
+
|
364
|
+
|
365
|
+
module EventMachine
|
366
|
+
|
367
|
+
class StreamObject < Selectable
|
368
|
+
def initialize io
|
369
|
+
super io
|
370
|
+
@outbound_q = []
|
371
|
+
end
|
372
|
+
|
373
|
+
# If we have to close, or a close-after-writing has been requested,
|
374
|
+
# then don't read any more data.
|
375
|
+
def select_for_reading?
|
376
|
+
true unless (@close_scheduled || @close_requested)
|
377
|
+
end
|
378
|
+
|
379
|
+
# If we have to close, don't select for writing.
|
380
|
+
# Otherwise, see if the protocol is ready to close.
|
381
|
+
# If not, see if he has data to send.
|
382
|
+
# If a close-after-writing has been requested and the outbound queue
|
383
|
+
# is empty, convert the status to close_scheduled.
|
384
|
+
def select_for_writing?
|
385
|
+
unless @close_scheduled
|
386
|
+
if @outbound_q.empty?
|
387
|
+
@close_scheduled = true if @close_requested
|
388
|
+
false
|
389
|
+
else
|
390
|
+
true
|
391
|
+
end
|
392
|
+
end
|
393
|
+
end
|
394
|
+
|
395
|
+
# Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
|
396
|
+
# If we have it, then we can read multiple times safely to improve
|
397
|
+
# performance.
|
398
|
+
# TODO, coalesce multiple reads into a single event.
|
399
|
+
# TODO, do the function check somewhere else and cache it.
|
400
|
+
def eventable_read
|
401
|
+
begin
|
402
|
+
if io.respond_to?(:read_nonblock)
|
403
|
+
10.times {
|
404
|
+
data = io.read_nonblock(4096)
|
405
|
+
EventMachine::event_callback uuid, ConnectionData, data
|
406
|
+
}
|
407
|
+
else
|
408
|
+
data = io.sysread(4096)
|
409
|
+
EventMachine::event_callback uuid, ConnectionData, data
|
410
|
+
end
|
411
|
+
rescue Errno::EAGAIN
|
412
|
+
# no-op
|
413
|
+
rescue Errno::ECONNRESET, EOFError
|
414
|
+
@close_scheduled = true
|
415
|
+
EventMachine::event_callback uuid, ConnectionUnbound, nil
|
416
|
+
end
|
417
|
+
|
418
|
+
end
|
419
|
+
|
420
|
+
# Provisional implementation. Will be re-implemented in subclasses.
|
421
|
+
# TODO: Complete this implementation. As it stands, this only writes
|
422
|
+
# a single packet per cycle. Highly inefficient, but required unless
|
423
|
+
# we're running on a Ruby with proper nonblocking I/O (Ruby 1.8.4
|
424
|
+
# built from sources from May 25, 2006 or newer).
|
425
|
+
# We need to improve the loop so it writes multiple times, however
|
426
|
+
# not more than a certain number of bytes per cycle, otherwise
|
427
|
+
# one busy connection could hog output buffers and slow down other
|
428
|
+
# connections. Also we should coalesce small writes.
|
429
|
+
# URGENT TODO: Coalesce small writes. They are a performance killer.
|
430
|
+
def eventable_write
|
431
|
+
# coalesce the outbound array here, perhaps
|
432
|
+
while data = @outbound_q.shift do
|
433
|
+
begin
|
434
|
+
data = data.to_s
|
435
|
+
w = if io.respond_to?(:write_nonblock)
|
436
|
+
io.write_nonblock data
|
437
|
+
else
|
438
|
+
io.syswrite data
|
439
|
+
end
|
440
|
+
|
441
|
+
if w < data.length
|
442
|
+
$outbound_q.unshift data[w..-1]
|
443
|
+
break
|
444
|
+
end
|
445
|
+
rescue Errno::EAGAIN
|
446
|
+
@outbound_q.unshift data
|
447
|
+
rescue EOFError, Errno::ECONNRESET
|
448
|
+
@close_scheduled = true
|
449
|
+
@outbound_q.clear
|
450
|
+
end
|
451
|
+
end
|
452
|
+
|
453
|
+
end
|
454
|
+
|
455
|
+
# #send_data
|
456
|
+
def send_data data
|
457
|
+
# TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
|
458
|
+
unless @close_scheduled or @close_requested or !data or data.length <= 0
|
459
|
+
@outbound_q << data.to_s
|
460
|
+
end
|
461
|
+
end
|
462
|
+
|
463
|
+
# #schedule_close
|
464
|
+
# The application wants to close the connection.
|
465
|
+
def schedule_close after_writing
|
466
|
+
if after_writing
|
467
|
+
@close_requested = true
|
468
|
+
else
|
469
|
+
@close_scheduled = true
|
470
|
+
end
|
471
|
+
end
|
472
|
+
|
473
|
+
# #get_peername
|
474
|
+
# This is defined in the normal way on connected stream objects.
|
475
|
+
# Return an object that is suitable for passing to Socket#unpack_sockaddr_in or variants.
|
476
|
+
# We could also use a convenience method that did the unpacking automatically.
|
477
|
+
def get_peername
|
478
|
+
io.getpeername
|
479
|
+
end
|
480
|
+
|
481
|
+
end
|
482
|
+
|
483
|
+
|
484
|
+
end
|
485
|
+
|
486
|
+
|
487
|
+
#--------------------------------------------------------------
|
488
|
+
|
489
|
+
|
490
|
+
|
491
|
+
module EventMachine
|
492
|
+
class EvmaTCPClient < StreamObject
|
493
|
+
|
494
|
+
def self.connect host, port
|
495
|
+
sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
496
|
+
begin
|
497
|
+
# TODO, this assumes a current Ruby snapshot.
|
498
|
+
# We need to degrade to a nonblocking connect otherwise.
|
499
|
+
sd.connect_nonblock( Socket.pack_sockaddr_in( port, host ))
|
500
|
+
rescue Errno::EINPROGRESS
|
501
|
+
end
|
502
|
+
EvmaTCPClient.new sd
|
503
|
+
end
|
504
|
+
|
505
|
+
|
506
|
+
def initialize io
|
507
|
+
super
|
508
|
+
@pending = true
|
509
|
+
end
|
510
|
+
|
511
|
+
|
512
|
+
def select_for_writing?
|
513
|
+
@pending ? true : super
|
514
|
+
end
|
515
|
+
|
516
|
+
def select_for_reading?
|
517
|
+
@pending ? false : super
|
518
|
+
end
|
519
|
+
|
520
|
+
def eventable_write
|
521
|
+
if @pending
|
522
|
+
@pending = false
|
523
|
+
EventMachine::event_callback uuid, ConnectionCompleted, ""
|
524
|
+
else
|
525
|
+
super
|
526
|
+
end
|
527
|
+
end
|
528
|
+
|
529
|
+
|
530
|
+
|
531
|
+
end
|
532
|
+
end
|
533
|
+
|
534
|
+
|
535
|
+
#--------------------------------------------------------------
|
536
|
+
|
537
|
+
module EventMachine
|
538
|
+
class EvmaTCPServer < Selectable
|
539
|
+
|
540
|
+
class << self
|
541
|
+
# Versions of ruby 1.8.4 later than May 26 2006 will work properly
|
542
|
+
# with an object of type TCPServer. Prior versions won't so we
|
543
|
+
# play it safe and just build a socket.
|
544
|
+
#
|
545
|
+
def start_server host, port
|
546
|
+
sd = Socket.new( Socket::AF_INET, Socket::SOCK_STREAM, 0 )
|
547
|
+
sd.setsockopt( Socket::SOL_SOCKET, Socket::SO_REUSEADDR, true )
|
548
|
+
sd.bind( Socket.pack_sockaddr_in( port, host ))
|
549
|
+
sd.listen( 50 ) # 5 is what you see in all the books. Ain't enough.
|
550
|
+
EvmaTCPServer.new sd
|
551
|
+
end
|
552
|
+
end
|
553
|
+
|
554
|
+
def initialize io
|
555
|
+
super io
|
556
|
+
end
|
557
|
+
|
558
|
+
|
559
|
+
def select_for_reading?
|
560
|
+
true
|
561
|
+
end
|
562
|
+
|
563
|
+
#--
|
564
|
+
# accept_nonblock returns an array consisting of the accepted
|
565
|
+
# socket and a sockaddr_in which names the peer.
|
566
|
+
# Don't accept more than 10 at a time.
|
567
|
+
def eventable_read
|
568
|
+
begin
|
569
|
+
10.times {
|
570
|
+
descriptor,peername = io.accept_nonblock
|
571
|
+
sd = StreamObject.new descriptor
|
572
|
+
EventMachine::event_callback uuid, ConnectionAccepted, sd.uuid
|
573
|
+
}
|
574
|
+
rescue Errno::EWOULDBLOCK, Errno::EAGAIN
|
575
|
+
end
|
576
|
+
end
|
577
|
+
|
578
|
+
|
579
|
+
end
|
580
|
+
end
|
581
|
+
|
582
|
+
|
583
|
+
|
584
|
+
#--------------------------------------------------------------
|
585
|
+
|
586
|
+
module EventMachine
|
587
|
+
class LoopbreakReader < Selectable
|
588
|
+
|
589
|
+
def select_for_reading?
|
590
|
+
true
|
591
|
+
end
|
592
|
+
|
593
|
+
def eventable_read
|
594
|
+
io.sysread(128)
|
595
|
+
EventMachine::event_callback "", LoopbreakSignalled, ""
|
596
|
+
end
|
597
|
+
|
598
|
+
end
|
599
|
+
end
|
600
|
+
|
601
|
+
#--------------------------------------------------------------
|
602
|
+
|
603
|
+
|
604
|
+
module EventMachine
|
605
|
+
|
606
|
+
class DatagramObject < Selectable
|
607
|
+
def initialize io
|
608
|
+
super io
|
609
|
+
@outbound_q = []
|
610
|
+
end
|
611
|
+
|
612
|
+
# #send_datagram
|
613
|
+
def send_datagram data, target
|
614
|
+
# TODO, coalesce here perhaps by being smarter about appending to @outbound_q.last?
|
615
|
+
unless @close_scheduled or @close_requested
|
616
|
+
@outbound_q << [data.to_s, target]
|
617
|
+
end
|
618
|
+
end
|
619
|
+
|
620
|
+
# #select_for_writing?
|
621
|
+
def select_for_writing?
|
622
|
+
unless @close_scheduled
|
623
|
+
if @outbound_q.empty?
|
624
|
+
@close_scheduled = true if @close_requested
|
625
|
+
false
|
626
|
+
else
|
627
|
+
true
|
628
|
+
end
|
629
|
+
end
|
630
|
+
end
|
631
|
+
|
632
|
+
# #select_for_reading?
|
633
|
+
def select_for_reading?
|
634
|
+
true
|
635
|
+
end
|
636
|
+
|
637
|
+
|
638
|
+
end
|
639
|
+
|
640
|
+
|
641
|
+
end
|
642
|
+
|
643
|
+
|
644
|
+
#--------------------------------------------------------------
|
645
|
+
|
646
|
+
module EventMachine
|
647
|
+
class EvmaUDPSocket < DatagramObject
|
648
|
+
|
649
|
+
class << self
|
650
|
+
def create host, port
|
651
|
+
sd = Socket.new( Socket::AF_INET, Socket::SOCK_DGRAM, 0 )
|
652
|
+
sd.bind Socket::pack_sockaddr_in( port, host )
|
653
|
+
EvmaUDPSocket.new sd
|
654
|
+
end
|
655
|
+
end
|
656
|
+
|
657
|
+
# #eventable_write
|
658
|
+
# This really belongs in DatagramObject, but there is some UDP-specific stuff.
|
659
|
+
def eventable_write
|
660
|
+
40.times {
|
661
|
+
break if @outbound_q.empty?
|
662
|
+
begin
|
663
|
+
data,target = @outbound_q.first
|
664
|
+
|
665
|
+
# This damn better be nonblocking.
|
666
|
+
io.send data.to_s, 0, target
|
667
|
+
|
668
|
+
@outbound_q.shift
|
669
|
+
rescue Errno::EAGAIN
|
670
|
+
# It's not been observed in testing that we ever get here.
|
671
|
+
# True to the definition, packets will be accepted and quietly dropped
|
672
|
+
# if the system is under pressure.
|
673
|
+
break
|
674
|
+
rescue EOFError, Errno::ECONNRESET
|
675
|
+
@close_scheduled = true
|
676
|
+
@outbound_q.clear
|
677
|
+
end
|
678
|
+
}
|
679
|
+
end
|
680
|
+
|
681
|
+
# Proper nonblocking I/O was added to Ruby 1.8.4 in May 2006.
|
682
|
+
# If we have it, then we can read multiple times safely to improve
|
683
|
+
# performance.
|
684
|
+
def eventable_read
|
685
|
+
begin
|
686
|
+
if io.respond_to?(:recvfrom_nonblock)
|
687
|
+
40.times {
|
688
|
+
data,@return_address = io.recvfrom_nonblock(16384)
|
689
|
+
EventMachine::event_callback uuid, ConnectionData, data
|
690
|
+
@return_address = nil
|
691
|
+
}
|
692
|
+
else
|
693
|
+
raise "unimplemented datagram-read operation on this Ruby"
|
694
|
+
end
|
695
|
+
rescue Errno::EAGAIN
|
696
|
+
# no-op
|
697
|
+
rescue Errno::ECONNRESET, EOFError
|
698
|
+
@close_scheduled = true
|
699
|
+
EventMachine::event_callback uuid, ConnectionUnbound, nil
|
700
|
+
end
|
701
|
+
|
702
|
+
end
|
703
|
+
|
704
|
+
|
705
|
+
def send_data data
|
706
|
+
send_datagram data, @return_address
|
707
|
+
end
|
708
|
+
|
709
|
+
end
|
710
|
+
end
|
711
|
+
|
712
|
+
#--------------------------------------------------------------
|
713
|
+
|
714
|
+
|