cool.io 1.4.1-x64-mingw32

Sign up to get free protection for your applications and to get access to all the features.
Files changed (76) hide show
  1. checksums.yaml +7 -0
  2. data/.gitignore +29 -0
  3. data/.rspec +3 -0
  4. data/.travis.yml +13 -0
  5. data/CHANGES.md +229 -0
  6. data/Gemfile +4 -0
  7. data/LICENSE +20 -0
  8. data/README.md +166 -0
  9. data/Rakefile +79 -0
  10. data/cool.io.gemspec +29 -0
  11. data/examples/callbacked_echo_server.rb +24 -0
  12. data/examples/dslified_echo_client.rb +34 -0
  13. data/examples/dslified_echo_server.rb +24 -0
  14. data/examples/echo_client.rb +38 -0
  15. data/examples/echo_server.rb +27 -0
  16. data/examples/google.rb +9 -0
  17. data/ext/cool.io/.gitignore +5 -0
  18. data/ext/cool.io/cool.io.h +59 -0
  19. data/ext/cool.io/cool.io_ext.c +25 -0
  20. data/ext/cool.io/ev_wrap.h +10 -0
  21. data/ext/cool.io/extconf.rb +61 -0
  22. data/ext/cool.io/iowatcher.c +189 -0
  23. data/ext/cool.io/libev.c +8 -0
  24. data/ext/cool.io/loop.c +261 -0
  25. data/ext/cool.io/stat_watcher.c +269 -0
  26. data/ext/cool.io/timer_watcher.c +219 -0
  27. data/ext/cool.io/utils.c +122 -0
  28. data/ext/cool.io/watcher.c +264 -0
  29. data/ext/cool.io/watcher.h +71 -0
  30. data/ext/iobuffer/extconf.rb +9 -0
  31. data/ext/iobuffer/iobuffer.c +767 -0
  32. data/ext/libev/Changes +507 -0
  33. data/ext/libev/LICENSE +37 -0
  34. data/ext/libev/README +58 -0
  35. data/ext/libev/README.embed +3 -0
  36. data/ext/libev/ev.c +5054 -0
  37. data/ext/libev/ev.h +853 -0
  38. data/ext/libev/ev_epoll.c +282 -0
  39. data/ext/libev/ev_kqueue.c +214 -0
  40. data/ext/libev/ev_poll.c +148 -0
  41. data/ext/libev/ev_port.c +185 -0
  42. data/ext/libev/ev_select.c +362 -0
  43. data/ext/libev/ev_vars.h +204 -0
  44. data/ext/libev/ev_win32.c +163 -0
  45. data/ext/libev/ev_wrap.h +200 -0
  46. data/ext/libev/ruby_gil.patch +97 -0
  47. data/ext/libev/test_libev_win32.c +123 -0
  48. data/ext/libev/win_select.patch +115 -0
  49. data/lib/.gitignore +2 -0
  50. data/lib/cool.io.rb +34 -0
  51. data/lib/cool.io/async_watcher.rb +43 -0
  52. data/lib/cool.io/custom_require.rb +9 -0
  53. data/lib/cool.io/dns_resolver.rb +219 -0
  54. data/lib/cool.io/dsl.rb +139 -0
  55. data/lib/cool.io/io.rb +194 -0
  56. data/lib/cool.io/iowatcher.rb +17 -0
  57. data/lib/cool.io/listener.rb +99 -0
  58. data/lib/cool.io/loop.rb +122 -0
  59. data/lib/cool.io/meta.rb +49 -0
  60. data/lib/cool.io/server.rb +75 -0
  61. data/lib/cool.io/socket.rb +230 -0
  62. data/lib/cool.io/timer_watcher.rb +17 -0
  63. data/lib/cool.io/version.rb +7 -0
  64. data/lib/coolio.rb +2 -0
  65. data/spec/async_watcher_spec.rb +57 -0
  66. data/spec/dns_spec.rb +43 -0
  67. data/spec/iobuffer_spec.rb +147 -0
  68. data/spec/spec_helper.rb +19 -0
  69. data/spec/stat_watcher_spec.rb +77 -0
  70. data/spec/tcp_server_spec.rb +225 -0
  71. data/spec/tcp_socket_spec.rb +185 -0
  72. data/spec/timer_watcher_spec.rb +59 -0
  73. data/spec/udp_socket_spec.rb +58 -0
  74. data/spec/unix_listener_spec.rb +25 -0
  75. data/spec/unix_server_spec.rb +27 -0
  76. metadata +182 -0
@@ -0,0 +1,139 @@
1
+ #--
2
+ # Copyright (C)2010 Tony Arcieri
3
+ # You can redistribute this under the terms of the Ruby license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ module Coolio
8
+ # A module we stash all the connections defined by the DSL under
9
+ module Connections; end
10
+
11
+ # A DSL for defining Cool.io connection types and servers
12
+ module DSL
13
+ # Define all methods on the metaclass
14
+ module_function
15
+
16
+ # Run the default Cool.io event loop
17
+ def run
18
+ Cool.io::Loop.default.run
19
+ end
20
+
21
+ # Connect to the given host and port using the given connection class
22
+ def connect(host, port, connection_name = nil, *initializer_args, &block)
23
+ if block_given?
24
+ initializer_args.unshift connection_name if connection_name
25
+
26
+ klass = Class.new Cool.io::TCPSocket
27
+ connection_builder = ConnectionBuilder.new klass
28
+ connection_builder.instance_eval(&block)
29
+ else
30
+ raise ArgumentError, "no connection name or block given" unless connection_name
31
+ klass = self[connection_name]
32
+ end
33
+
34
+ client = klass.connect host, port, *initializer_args
35
+ client.attach Cool.io::Loop.default
36
+ client
37
+ end
38
+
39
+ # Create a new Cool.io::TCPServer
40
+ def server(host, port, connection_name = nil, *initializer_args, &block)
41
+ if block_given?
42
+ initializer_args.unshift connection_name if connection_name
43
+
44
+ klass = Class.new Cool.io::TCPSocket
45
+ connection_builder = ConnectionBuilder.new klass
46
+ connection_builder.instance_eval(&block)
47
+ else
48
+ raise ArgumentError, "no connection name or block given" unless connection_name
49
+ klass = self[connection_name]
50
+ end
51
+
52
+ server = Cool.io::TCPServer.new host, port, klass, *initializer_args
53
+ server.attach Cool.io::Loop.default
54
+ server
55
+ end
56
+
57
+ # Create a new Cool.io::TCPSocket class
58
+ def connection(name, &block)
59
+ # Camelize class name
60
+ class_name = name.to_s.split('_').map { |s| s.capitalize }.join
61
+
62
+ connection = Class.new Cool.io::TCPSocket
63
+ connection_builder = ConnectionBuilder.new connection
64
+ connection_builder.instance_eval(&block)
65
+
66
+ Coolio::Connections.const_set class_name, connection
67
+ end
68
+
69
+ # Look up a connection class by its name
70
+ def [](connection_name)
71
+ class_name = connection_name.to_s.split('_').map { |s| s.capitalize }.join
72
+
73
+ begin
74
+ Coolio::Connections.const_get class_name
75
+ rescue NameError
76
+ raise NameError, "No connection type registered for #{connection_name.inspect}"
77
+ end
78
+ end
79
+
80
+ # Builder for Cool.io::TCPSocket classes
81
+ class ConnectionBuilder
82
+ def initialize(klass)
83
+ @klass = klass
84
+ end
85
+
86
+ # Declare an initialize function
87
+ def initializer(&action)
88
+ @klass.send :define_method, :initialize, &action
89
+ end
90
+
91
+ # Declare the on_connect callback
92
+ def on_connect(&action)
93
+ @klass.send :define_method, :on_connect, &action
94
+ end
95
+
96
+ # Declare a callback fired if we failed to connect
97
+ def on_connect_failed(&action)
98
+ @klass.send :define_method, :on_connect_failed, &action
99
+ end
100
+
101
+ # Declare a callback fired if DNS resolution failed
102
+ def on_resolve_failed(&action)
103
+ @klass.send :define_method, :on_resolve_failed, &action
104
+ end
105
+
106
+ # Declare the on_close callback
107
+ def on_close(&action)
108
+ @klass.send :define_method, :on_close, &action
109
+ end
110
+
111
+ # Declare the on_read callback
112
+ def on_read(&action)
113
+ @klass.send :define_method, :on_read, &action
114
+ end
115
+
116
+ # Declare the on_write_complete callback
117
+ def on_write_complete(&action)
118
+ @klass.send :define_method, :on_write_complete, &action
119
+ end
120
+ end
121
+ end
122
+ end
123
+
124
+ # The Cool module containing all our coolness
125
+ module Cool
126
+ module Coolness
127
+ def cool
128
+ Cool::IOThunk
129
+ end
130
+ end
131
+
132
+ module IOThunk
133
+ def self.io
134
+ Coolio::DSL
135
+ end
136
+ end
137
+ end
138
+
139
+ extend Cool::Coolness
@@ -0,0 +1,194 @@
1
+ #--
2
+ # Copyright (C)2007-10 Tony Arcieri
3
+ # You can redistribute this under the terms of the Ruby license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ module Coolio
8
+ # A buffered I/O class witch fits into the Coolio Watcher framework.
9
+ # It provides both an observer which reads data as it's received
10
+ # from the wire and a buffered write watcher which stores data and writes
11
+ # it out each time the socket becomes writable.
12
+ #
13
+ # This class is primarily meant as a base class for other streams
14
+ # which need non-blocking writing, and is used to implement Coolio's
15
+ # Socket class and its associated subclasses.
16
+ class IO
17
+ extend Meta
18
+
19
+ # Maximum number of bytes to consume at once
20
+ INPUT_SIZE = 16384
21
+
22
+ def initialize(io)
23
+ @_io = io
24
+ @_write_buffer ||= ::IO::Buffer.new
25
+ @_read_watcher = Watcher.new(io, self, :r)
26
+ @_write_watcher = Watcher.new(io, self, :w)
27
+ end
28
+
29
+ #
30
+ # Watcher methods, delegated to @_read_watcher
31
+ #
32
+
33
+ # Attach to the event loop
34
+ def attach(loop)
35
+ @_read_watcher.attach(loop)
36
+ schedule_write if !@_write_buffer.empty?
37
+ self
38
+ end
39
+
40
+ # Detach from the event loop
41
+ def detach
42
+ # TODO should these detect write buffers, as well?
43
+ @_read_watcher.detach
44
+ self
45
+ end
46
+
47
+ # Enable the watcher
48
+ def enable
49
+ @_read_watcher.enable
50
+ self
51
+ end
52
+
53
+ # Disable the watcher
54
+ def disable
55
+ @_read_watcher.disable
56
+ self
57
+ end
58
+
59
+ # Is the watcher attached?
60
+ def attached?
61
+ @_read_watcher.attached?
62
+ end
63
+
64
+ # Is the watcher enabled?
65
+ def enabled?
66
+ @_read_watcher.enabled?
67
+ end
68
+
69
+ # Obtain the event loop associated with this object
70
+ def evloop
71
+ @_read_watcher.evloop
72
+ end
73
+
74
+ #
75
+ # Callbacks for asynchronous events
76
+ #
77
+
78
+ # Called whenever the IO object receives data
79
+ def on_read(data); end
80
+ event_callback :on_read
81
+
82
+ # Called whenever a write completes and the output buffer is empty
83
+ def on_write_complete; end
84
+ event_callback :on_write_complete
85
+
86
+ # Called whenever the IO object hits EOF
87
+ def on_close; end
88
+ event_callback :on_close
89
+
90
+ #
91
+ # Write interface
92
+ #
93
+
94
+ # Write data in a buffered, non-blocking manner
95
+ def write(data)
96
+ @_write_buffer << data
97
+ schedule_write
98
+ data.size
99
+ end
100
+
101
+ # Close the IO stream
102
+ def close
103
+ detach if attached?
104
+ detach_write_watcher
105
+ @_io.close unless closed?
106
+
107
+ on_close
108
+ nil
109
+ end
110
+
111
+ # Is the IO object closed?
112
+ def closed?
113
+ @_io.nil? or @_io.closed?
114
+ end
115
+
116
+ #########
117
+ protected
118
+ #########
119
+
120
+ # Read from the input buffer and dispatch to on_read
121
+ def on_readable
122
+ begin
123
+ on_read @_io.read_nonblock(INPUT_SIZE)
124
+ rescue Errno::EAGAIN, Errno::EINTR
125
+ return
126
+
127
+ # SystemCallError catches Errno::ECONNRESET amongst others.
128
+ rescue SystemCallError, EOFError, IOError, SocketError
129
+ close
130
+ end
131
+ end
132
+
133
+ # Write the contents of the output buffer
134
+ def on_writable
135
+ begin
136
+ @_write_buffer.write_to(@_io)
137
+ rescue Errno::EINTR
138
+ return
139
+
140
+ # SystemCallError catches Errno::EPIPE & Errno::ECONNRESET amongst others.
141
+ rescue SystemCallError, IOError, SocketError
142
+ return close
143
+ end
144
+
145
+ if @_write_buffer.empty?
146
+ disable_write_watcher
147
+ on_write_complete
148
+ end
149
+ end
150
+
151
+ # Schedule a write to be performed when the IO object becomes writable
152
+ def schedule_write
153
+ return unless @_io # this would mean 'we are still pre DNS here'
154
+ return unless @_read_watcher.attached? # this would mean 'currently unattached' -- ie still pre DNS, or just plain not attached, which is ok
155
+ begin
156
+ enable_write_watcher
157
+ rescue IOError
158
+ end
159
+ end
160
+
161
+ def enable_write_watcher
162
+ if @_write_watcher.attached?
163
+ @_write_watcher.enable unless @_write_watcher.enabled?
164
+ else
165
+ @_write_watcher.attach(evloop)
166
+ end
167
+ end
168
+
169
+ def disable_write_watcher
170
+ @_write_watcher.disable if @_write_watcher and @_write_watcher.enabled?
171
+ end
172
+
173
+ def detach_write_watcher
174
+ @_write_watcher.detach if @_write_watcher and @_write_watcher.attached?
175
+ end
176
+
177
+ # Internal class implementing watchers used by Coolio::IO
178
+ class Watcher < IOWatcher
179
+ def initialize(ruby_io, coolio_io, flags)
180
+ @coolio_io = coolio_io
181
+ super(ruby_io, flags)
182
+ end
183
+
184
+ # Configure IOWatcher event callbacks to call the method passed to #initialize
185
+ def on_readable
186
+ @coolio_io.__send__(:on_readable)
187
+ end
188
+
189
+ def on_writable
190
+ @coolio_io.__send__(:on_writable)
191
+ end
192
+ end
193
+ end
194
+ end
@@ -0,0 +1,17 @@
1
+ #--
2
+ # Copyright (C)2007-10 Tony Arcieri
3
+ # You can redistribute this under the terms of the Ruby license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ module Coolio
8
+ class IOWatcher
9
+ # The actual implementation of this class resides in the C extension
10
+ # Here we metaprogram proper event_callbacks for the callback methods
11
+ # These can take a block and store it to be called when the event
12
+ # is actually fired.
13
+
14
+ extend Meta
15
+ event_callback :on_readable, :on_writable
16
+ end
17
+ end
@@ -0,0 +1,99 @@
1
+ #--
2
+ # Copyright (C)2007-10 Tony Arcieri
3
+ # You can redistribute this under the terms of the Ruby license
4
+ # See file LICENSE for details
5
+ #++
6
+
7
+ require 'socket'
8
+
9
+ module Coolio
10
+ # Listeners wait for incoming connections. When a listener receives a
11
+ # connection it fires the on_connection event with the newly accepted
12
+ # socket as a parameter.
13
+ class Listener < IOWatcher
14
+ def initialize(listen_socket)
15
+ @listen_socket = listen_socket
16
+ super(@listen_socket)
17
+ end
18
+
19
+ # Returns an integer representing the underlying numeric file descriptor
20
+ def fileno
21
+ @listen_socket.fileno
22
+ end
23
+
24
+ def listen(backlog)
25
+ @listen_socket.listen(backlog)
26
+ end
27
+
28
+ # Close the listener
29
+ def close
30
+ detach if attached?
31
+ @listen_socket.close
32
+ end
33
+
34
+ # Called whenever the server receives a new connection
35
+ def on_connection(socket); end
36
+ event_callback :on_connection
37
+
38
+ #########
39
+ protected
40
+ #########
41
+
42
+ # Coolio callback for handling new connections
43
+ def on_readable
44
+ begin
45
+ on_connection @listen_socket.accept_nonblock
46
+ rescue Errno::EAGAIN, Errno::ECONNABORTED
47
+ # EAGAIN can be triggered here if the socket is shared between
48
+ # multiple processes and a thundering herd is woken up to accept
49
+ # one connection, only one process will get the connection and
50
+ # the others will be awoken.
51
+ # ECONNABORTED is documented in accept() manpages but modern TCP
52
+ # stacks with syncookies and/or accept()-filtering for DoS
53
+ # protection do not see it. In any case this error is harmless
54
+ # and we should instead spend our time with clients that follow
55
+ # through on connection attempts.
56
+ end
57
+ end
58
+ end
59
+
60
+ DEFAULT_BACKLOG = 1024
61
+
62
+ class TCPListener < Listener
63
+ # Create a new Coolio::TCPListener on the specified address and port.
64
+ # Accepts the following options:
65
+ #
66
+ # :backlog - Max size of the pending connection queue (default 1024)
67
+ # :reverse_lookup - Retain BasicSocket's reverse DNS functionality (default false)
68
+ #
69
+ # If the specified address is an TCPServer object, it will ignore
70
+ # the port and :backlog option and create a new Coolio::TCPListener out
71
+ # of the existing TCPServer object.
72
+ def initialize(addr, port = nil, options = {})
73
+ BasicSocket.do_not_reverse_lookup = true unless options[:reverse_lookup]
74
+ options[:backlog] ||= DEFAULT_BACKLOG
75
+
76
+ listen_socket = if ::TCPServer === addr
77
+ addr
78
+ else
79
+ raise ArgumentError, "port must be an integer" if nil == port
80
+ ::TCPServer.new(addr, port)
81
+ end
82
+ listen_socket.instance_eval { listen(options[:backlog]) }
83
+ super(listen_socket)
84
+ end
85
+ end
86
+
87
+ class UNIXListener < Listener
88
+ # Create a new Coolio::UNIXListener
89
+ #
90
+ # Accepts the same arguments as UNIXServer.new
91
+ # Optionally, it can also take anyn existing UNIXServer object
92
+ # and create a Coolio::UNIXListener out of it.
93
+ def initialize(*args)
94
+ s = ::UNIXServer === args.first ? args.first : ::UNIXServer.new(*args)
95
+ s.instance_eval { listen(DEFAULT_BACKLOG) }
96
+ super(s)
97
+ end
98
+ end
99
+ end