cool.io 1.2.0-x86-mswin32-60

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 (79) hide show
  1. data/.gitignore +26 -0
  2. data/.rspec +3 -0
  3. data/.travis.yml +5 -0
  4. data/CHANGES.md +177 -0
  5. data/Gemfile +4 -0
  6. data/LICENSE +20 -0
  7. data/README.md +172 -0
  8. data/Rakefile +81 -0
  9. data/cool.io.gemspec +28 -0
  10. data/examples/dslified_echo_client.rb +34 -0
  11. data/examples/dslified_echo_server.rb +24 -0
  12. data/examples/echo_client.rb +38 -0
  13. data/examples/echo_server.rb +27 -0
  14. data/examples/google.rb +9 -0
  15. data/examples/httpclient.rb +38 -0
  16. data/ext/cool.io/.gitignore +5 -0
  17. data/ext/cool.io/cool.io.h +58 -0
  18. data/ext/cool.io/cool.io_ext.c +25 -0
  19. data/ext/cool.io/ev_wrap.h +8 -0
  20. data/ext/cool.io/extconf.rb +73 -0
  21. data/ext/cool.io/iowatcher.c +189 -0
  22. data/ext/cool.io/libev.c +8 -0
  23. data/ext/cool.io/loop.c +301 -0
  24. data/ext/cool.io/stat_watcher.c +269 -0
  25. data/ext/cool.io/timer_watcher.c +219 -0
  26. data/ext/cool.io/utils.c +122 -0
  27. data/ext/cool.io/watcher.c +264 -0
  28. data/ext/cool.io/watcher.h +71 -0
  29. data/ext/http11_client/.gitignore +5 -0
  30. data/ext/http11_client/LICENSE +31 -0
  31. data/ext/http11_client/ext_help.h +14 -0
  32. data/ext/http11_client/extconf.rb +6 -0
  33. data/ext/http11_client/http11_client.c +300 -0
  34. data/ext/http11_client/http11_parser.c +403 -0
  35. data/ext/http11_client/http11_parser.h +48 -0
  36. data/ext/http11_client/http11_parser.rl +173 -0
  37. data/ext/iobuffer/extconf.rb +9 -0
  38. data/ext/iobuffer/iobuffer.c +765 -0
  39. data/ext/libev/Changes +388 -0
  40. data/ext/libev/LICENSE +36 -0
  41. data/ext/libev/README +58 -0
  42. data/ext/libev/README.embed +3 -0
  43. data/ext/libev/ev.c +4803 -0
  44. data/ext/libev/ev.h +845 -0
  45. data/ext/libev/ev_epoll.c +279 -0
  46. data/ext/libev/ev_kqueue.c +214 -0
  47. data/ext/libev/ev_poll.c +148 -0
  48. data/ext/libev/ev_port.c +185 -0
  49. data/ext/libev/ev_select.c +314 -0
  50. data/ext/libev/ev_vars.h +203 -0
  51. data/ext/libev/ev_win32.c +163 -0
  52. data/ext/libev/ev_wrap.h +200 -0
  53. data/ext/libev/test_libev_win32.c +123 -0
  54. data/lib/.gitignore +2 -0
  55. data/lib/cool.io.rb +32 -0
  56. data/lib/cool.io/async_watcher.rb +43 -0
  57. data/lib/cool.io/custom_require.rb +9 -0
  58. data/lib/cool.io/dns_resolver.rb +225 -0
  59. data/lib/cool.io/dsl.rb +135 -0
  60. data/lib/cool.io/eventmachine.rb +234 -0
  61. data/lib/cool.io/http_client.rb +427 -0
  62. data/lib/cool.io/io.rb +174 -0
  63. data/lib/cool.io/iowatcher.rb +17 -0
  64. data/lib/cool.io/listener.rb +93 -0
  65. data/lib/cool.io/loop.rb +130 -0
  66. data/lib/cool.io/meta.rb +49 -0
  67. data/lib/cool.io/server.rb +74 -0
  68. data/lib/cool.io/socket.rb +230 -0
  69. data/lib/cool.io/timer_watcher.rb +17 -0
  70. data/lib/cool.io/version.rb +5 -0
  71. data/lib/coolio.rb +2 -0
  72. data/spec/async_watcher_spec.rb +57 -0
  73. data/spec/dns_spec.rb +39 -0
  74. data/spec/spec_helper.rb +12 -0
  75. data/spec/stat_watcher_spec.rb +77 -0
  76. data/spec/timer_watcher_spec.rb +55 -0
  77. data/spec/unix_listener_spec.rb +25 -0
  78. data/spec/unix_server_spec.rb +25 -0
  79. metadata +200 -0
@@ -0,0 +1,74 @@
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 Server < Listener
9
+ # Servers listen for incoming connections and create new connection objects
10
+ # whenever incoming connections are received. The default class for new
11
+ # connections is a Socket, but any subclass of IOWatcher is acceptable.
12
+ def initialize(listen_socket, klass = Socket, *args, &block)
13
+ # Ensure the provided class responds to attach
14
+ unless klass.allocate.is_a? IO
15
+ raise ArgumentError, "can't convert #{klass} to Coolio::IO"
16
+ end
17
+
18
+ # Verify the arity of the provided arguments
19
+ arity = klass.instance_method(:initialize).arity
20
+ expected = arity >= 0 ? arity : -(arity + 1)
21
+
22
+ if (arity >= 0 and args.size + 1 != expected) or (arity < 0 and args.size + 1 < expected)
23
+ raise ArgumentError, "wrong number of arguments for #{klass}#initialize (#{args.size+1} for #{expected})"
24
+ end
25
+
26
+ @klass, @args, @block = klass, args, block
27
+ super(listen_socket)
28
+ end
29
+
30
+ # Returns an integer representing the underlying numeric file descriptor
31
+ def fileno
32
+ @listen_socket.fileno
33
+ end
34
+
35
+ #########
36
+ protected
37
+ #########
38
+
39
+ def on_connection(socket)
40
+ connection = @klass.new(socket, *@args).attach(evloop)
41
+ connection.__send__(:on_connect)
42
+ @block.call(connection) if @block
43
+ end
44
+ end
45
+
46
+ # TCP server class. Listens on the specified host and port and creates
47
+ # new connection objects of the given class. This is the most common server class.
48
+ # Note that the new connection objects will be bound by default to the same event loop that the server is attached to.
49
+ # Optionally, it can also take any existing core TCPServer object as
50
+ # +host+ and create a Coolio::TCPServer out of it.
51
+ class TCPServer < Server
52
+ def initialize(host, port = nil, klass = TCPSocket, *args, &block)
53
+ listen_socket = if ::TCPServer === host
54
+ host
55
+ else
56
+ raise ArgumentError, "port must be an integer" if nil == port
57
+ ::TCPServer.new(host, port)
58
+ end
59
+ listen_socket.instance_eval { listen(1024) } # Change listen backlog to 1024
60
+ super(listen_socket, klass, *args, &block)
61
+ end
62
+ end
63
+
64
+ # UNIX server class. Listens on the specified UNIX domain socket and
65
+ # creates new connection objects of the given class.
66
+ # Optionally, it can also take any existing core UNIXServer object as
67
+ # +path+ and create a Coolio::UNIXServer out of it.
68
+ class UNIXServer < Server
69
+ def initialize(path, klass = UNIXSocket, *args, &block)
70
+ s = ::UNIXServer === path ? path : ::UNIXServer.new(path)
71
+ super(s, klass, *args, &block)
72
+ end
73
+ end
74
+ end
@@ -0,0 +1,230 @@
1
+ #--
2
+ # Copyright (C)2007 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
+ require 'resolv'
9
+
10
+ module Coolio
11
+ class Socket < IO
12
+ def self.connect(socket, *args)
13
+
14
+ new(socket, *args).instance_eval do
15
+ @_connector = Connector.new(self, socket)
16
+ self
17
+ end
18
+ end
19
+
20
+ # Just initializes some instance variables to avoid
21
+ # warnings and calls super().
22
+ def initialize *args
23
+ @_failed = nil
24
+ @_connector = nil
25
+ super
26
+ end
27
+
28
+ watcher_delegate :@_connector
29
+
30
+ def attach(evloop)
31
+ raise RuntimeError, "connection failed" if @_failed
32
+
33
+ if @_connector
34
+ @_connector.attach(evloop)
35
+ return self
36
+ end
37
+
38
+ super
39
+ end
40
+
41
+ # Called upon completion of a socket connection
42
+ def on_connect; end
43
+ event_callback :on_connect
44
+
45
+ # Called if a socket connection failed to complete
46
+ def on_connect_failed; end
47
+ event_callback :on_connect_failed
48
+
49
+ # Called if a hostname failed to resolve when connecting
50
+ # Defaults to calling on_connect_failed
51
+ alias_method :on_resolve_failed, :on_connect_failed
52
+
53
+ #########
54
+ protected
55
+ #########
56
+
57
+ class Connector < IOWatcher
58
+ def initialize(coolio_socket, ruby_socket)
59
+ @coolio_socket, @ruby_socket = coolio_socket, ruby_socket
60
+ super(ruby_socket, :w)
61
+ end
62
+
63
+ def on_writable
64
+ evl = evloop
65
+ detach
66
+
67
+ if connect_successful?
68
+ @coolio_socket.instance_eval { @_connector = nil }
69
+ @coolio_socket.attach(evl)
70
+ @ruby_socket.setsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, [1].pack("l"))
71
+ @ruby_socket.setsockopt(::Socket::SOL_SOCKET, ::Socket::SO_KEEPALIVE, true)
72
+
73
+ @coolio_socket.__send__(:on_connect)
74
+ else
75
+ @coolio_socket.instance_eval { @_failed = true }
76
+ @coolio_socket.__send__(:on_connect_failed)
77
+ end
78
+ end
79
+
80
+ #######
81
+ private
82
+ #######
83
+
84
+ def connect_successful?
85
+ @ruby_socket.getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_ERROR).unpack('i').first == 0
86
+ rescue IOError
87
+ false
88
+ end
89
+ end
90
+ end
91
+
92
+ class TCPSocket < Socket
93
+ attr_reader :remote_host, :remote_addr, :remote_port, :address_family
94
+ watcher_delegate :@_resolver
95
+
96
+ # Similar to .new, but used in cases where the resulting object is in a
97
+ # "half-open" state. This is primarily used for when asynchronous
98
+ # DNS resolution is taking place. We don't actually have a handle to
99
+ # the socket we want to use to create the watcher yet, since we don't
100
+ # know the IP address to connect to.
101
+ def self.precreate(*args, &block)
102
+ obj = allocate
103
+ obj.__send__(:preinitialize, *args, &block)
104
+ obj
105
+ end
106
+
107
+ # Perform a non-blocking connect to the given host and port
108
+ # see examples/echo_client.rb
109
+ # addr is a string, can be an IP address or a hostname.
110
+ def self.connect(addr, port, *args)
111
+ family = nil
112
+
113
+ if (Resolv::IPv4.create(addr) rescue nil)
114
+ family = ::Socket::AF_INET
115
+ elsif(Resolv::IPv6.create(addr) rescue nil)
116
+ family = ::Socket::AF_INET6
117
+ end
118
+
119
+ if family
120
+ return super(TCPConnectSocket.new(family, addr, port), *args) # this creates a 'real' write buffer so we're ok there with regards to already having a write buffer from the get go
121
+ end
122
+
123
+ if host = Coolio::DNSResolver.hosts(addr)
124
+ return connect(host, port, *args) # calls this same function
125
+ end
126
+
127
+ precreate(addr, port, *args)
128
+ end
129
+
130
+ # Called by precreate during asyncronous DNS resolution
131
+ def preinitialize(addr, port, *args)
132
+ @_write_buffer = ::IO::Buffer.new # allow for writing BEFORE DNS has resolved
133
+ @remote_host, @remote_addr, @remote_port = addr, addr, port
134
+ @_resolver = TCPConnectResolver.new(self, addr, port, *args)
135
+ end
136
+
137
+ private :preinitialize
138
+
139
+ def initialize(socket)
140
+ unless socket.is_a?(::TCPSocket) or socket.is_a?(TCPConnectSocket)
141
+ raise TypeError, "socket must be a TCPSocket"
142
+ end
143
+
144
+ super
145
+
146
+ @address_family, @remote_port, @remote_host, @remote_addr = socket.peeraddr
147
+ end
148
+
149
+ def peeraddr
150
+ [@address_family, @remote_port, @remote_host, @remote_addr]
151
+ end
152
+
153
+ #########
154
+ protected
155
+ #########
156
+
157
+ class TCPConnectSocket < ::Socket
158
+ def initialize(family, addr, port, host = addr)
159
+ @host, @addr, @port = host, addr, port
160
+ @address_family = nil
161
+
162
+ super(family, ::Socket::SOCK_STREAM, 0)
163
+ begin
164
+ connect_nonblock(::Socket.sockaddr_in(port, addr))
165
+ rescue Errno::EINPROGRESS
166
+ end
167
+ end
168
+
169
+ def peeraddr
170
+ [
171
+ @address_family == ::Socket::AF_INET ? 'AF_INET' : 'AF_INET6',
172
+ @port,
173
+ @host,
174
+ @addr
175
+ ]
176
+ end
177
+ end
178
+
179
+ class TCPConnectResolver < Coolio::DNSResolver
180
+ def initialize(socket, host, port, *args)
181
+ @sock, @host, @port, @args = socket, host, port, args
182
+ super(host)
183
+ end
184
+
185
+ def on_success(addr)
186
+ host, port, args = @host, @port, @args
187
+
188
+ @sock.instance_eval do
189
+ # DNSResolver only supports IPv4 so we can safely assume IPv4 address
190
+ begin
191
+ socket = TCPConnectSocket.new(::Socket::AF_INET, addr, port, host)
192
+ rescue Errno::ENETUNREACH
193
+ on_connect_failed
194
+ return
195
+ end
196
+
197
+ initialize(socket, *args)
198
+ @_connector = Socket::Connector.new(self, socket)
199
+ @_resolver = nil
200
+ end
201
+ @sock.attach(evloop)
202
+ end
203
+
204
+ def on_failure
205
+ @sock.__send__(:on_resolve_failed)
206
+ @sock.instance_eval do
207
+ @_resolver = nil
208
+ @_failed = true
209
+ end
210
+ return
211
+ end
212
+ end
213
+ end
214
+
215
+ class UNIXSocket < Socket
216
+ attr_reader :path, :address_family
217
+
218
+ # Connect to the given UNIX domain socket
219
+ def self.connect(path, *args)
220
+ new(::UNIXSocket.new(path), *args)
221
+ end
222
+
223
+ def initialize(socket)
224
+ raise ArgumentError, "socket must be a UNIXSocket" unless socket.is_a? ::UNIXSocket
225
+
226
+ super
227
+ @address_family, @path = socket.peeraddr
228
+ end
229
+ end
230
+ end
@@ -0,0 +1,17 @@
1
+ #--
2
+ # Copyright (C)2007 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 TimerWatcher
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_timer
16
+ end
17
+ end
@@ -0,0 +1,5 @@
1
+ module Coolio
2
+ VERSION = "1.2.0"
3
+
4
+ def self.version; VERSION; end
5
+ end
data/lib/coolio.rb ADDED
@@ -0,0 +1,2 @@
1
+ # For those people who don't like the cool.io styling...
2
+ require 'cool.io'
@@ -0,0 +1,57 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+ require 'tempfile'
3
+ require 'fcntl'
4
+
5
+ describe Cool.io::AsyncWatcher, :env => :win do
6
+
7
+ it "does not signal on spurious wakeups" do
8
+ aw = Cool.io::AsyncWatcher.new
9
+ tmp = Tempfile.new('coolio_async_watcher_test')
10
+ nr_fork = 2 # must be at least two for spurious wakeups
11
+
12
+ # We have aetter chance of failing if this overflows the pipe buffer
13
+ # which POSIX requires >= 512 bytes, Linux 2.6 uses 4096 bytes
14
+ nr_signal = 4096 * 4
15
+
16
+ append = File.open(tmp.path, "ab")
17
+ append.sync = true
18
+ rd, wr = ::IO.pipe
19
+
20
+ aw.on_signal { append.syswrite("#$$\n") }
21
+ children = nr_fork.times.map do
22
+ fork do
23
+ trap(:TERM) { exit!(0) }
24
+ rloop = Cool.io::Loop.default
25
+ aw.attach(rloop)
26
+ wr.write '.' # signal to master that we're ready
27
+ rloop.run
28
+ exit!(1) # should not get here
29
+ end
30
+ end
31
+
32
+ # ensure children are ready
33
+ nr_fork.times { rd.sysread(1).should == '.' }
34
+
35
+ # send our signals
36
+ nr_signal.times { aw.signal }
37
+
38
+ # wait for the pipe buffer to be consumed by the children
39
+ sleep 1 while tmp.stat.ctime >= (Time.now - 4)
40
+
41
+ children.each do |pid|
42
+ Process.kill(:TERM, pid)
43
+ _, status = Process.waitpid2(pid)
44
+ status.exitstatus.should == 0
45
+ end
46
+
47
+ # we should've written a line for every signal we sent
48
+ lines = tmp.readlines
49
+ lines.size.should == nr_signal
50
+
51
+ # theoretically a bad kernel scheduler could give us fewer...
52
+ lines.sort.uniq.size.should == nr_fork
53
+
54
+ tmp.close!
55
+ end
56
+
57
+ end
data/spec/dns_spec.rb ADDED
@@ -0,0 +1,39 @@
1
+ require File.expand_path('../spec_helper', __FILE__)
2
+
3
+ VALID_DOMAIN = "google.com"
4
+ INVALID_DOMAIN = "gibidigibigididibitidibigitibidigitidididi.com"
5
+
6
+ class ItWorked < StandardError; end
7
+ class WontResolve < StandardError; end
8
+
9
+ class ConnectorThingy < Cool.io::TCPSocket
10
+ def on_connect
11
+ raise ItWorked
12
+ end
13
+
14
+ def on_resolve_failed
15
+ raise WontResolve
16
+ end
17
+ end
18
+
19
+ describe "DNS" do
20
+ before :each do
21
+ @loop = Cool.io::Loop.new
22
+ end
23
+
24
+ it "connects to valid domains" do
25
+ ConnectorThingy.connect(VALID_DOMAIN, 80).attach(@loop)
26
+
27
+ proc do
28
+ @loop.run
29
+ end.should raise_error(ItWorked)
30
+ end
31
+
32
+ it "fires on_resolve_failed for invalid domains" do
33
+ ConnectorThingy.connect(INVALID_DOMAIN, 80).attach(@loop)
34
+
35
+ proc do
36
+ @loop.run
37
+ end.should raise_error(WontResolve)
38
+ end
39
+ end
@@ -0,0 +1,12 @@
1
+ $LOAD_PATH.unshift File.dirname(__FILE__)
2
+ $LOAD_PATH.unshift File.expand_path('../../lib', __FILE__)
3
+
4
+ require 'rspec'
5
+ require 'cool.io'
6
+
7
+ RSpec.configure do |c|
8
+ if RUBY_PLATFORM =~ /mingw|win32/
9
+ $stderr.puts "Skip some specs on Windows"
10
+ c.filter_run_excluding :env => :win
11
+ end
12
+ end