async-dns 0.10.0 → 0.12.0

Sign up to get free protection for your applications and to get access to all the features.
checksums.yaml CHANGED
@@ -1,7 +1,7 @@
1
1
  ---
2
2
  SHA1:
3
- metadata.gz: 0d06ded8c25acd3d3b198a45c291b47f70d26667
4
- data.tar.gz: 708bfec661ce872d73137142ad338198f548a750
3
+ metadata.gz: 0302e920c59ef8d4ce72eaa34c0a442536304590
4
+ data.tar.gz: eede22f4c518bfa0dcf094933083aeda33bc82a1
5
5
  SHA512:
6
- metadata.gz: 33fe2f59bf6907af89631f9b6bf13e05e8312df6d1d197cc2b530edc2e7d9a29581988830494127aaef4d95f5cdf775511e828b55c210ab07d8a6337c1281fba
7
- data.tar.gz: b61ea4a2c6a9a336690165dbaa6e2789aaaccc53fb78e65e0dabc8a8ea99221b3c7d137020fac0f0e4dbe768f832fb5ab0ae72b9e9578989b3818107beba5c5c
6
+ metadata.gz: 60687d211cdcee0afecee281daa5ae79322713b0adff0baf78f2c82ef700ebe99e056dc5f40d14a059f3a0d5a18c5741091b2a20cfe61bb8efd184b201c789a3
7
+ data.tar.gz: '052292c7a58dcbfa650d902a7c7b15097fe1d7e1dd2b06ebda5d5009f68c7fc3ed130cbaeb36be26ee0a8f04b0099d7be080e028bcbe35016661e75c4d76f6cb'
@@ -0,0 +1,14 @@
1
+ /.bundle/
2
+ /.yardoc
3
+ /Gemfile.lock
4
+ /_yardoc/
5
+ /coverage/
6
+ /doc/
7
+ /pkg/
8
+ /spec/reports/
9
+ /tmp/
10
+
11
+ /spec/**/log/
12
+
13
+ # rspec failure tracking
14
+ .rspec_status
@@ -1,18 +1,19 @@
1
1
  language: ruby
2
2
  sudo: false
3
+ dist: trusty
4
+ cache: bundler
3
5
  addons:
4
6
  apt:
5
7
  packages:
6
8
  - bind9
7
9
  rvm:
8
- - 2.2.6
9
- - 2.3.3
10
- - 2.4.0
11
- - rbx-2
10
+ - 2.1
11
+ - 2.2
12
+ - 2.3
13
+ - 2.4
12
14
  - ruby-head
13
15
  - jruby-head
14
16
  matrix:
15
17
  allow_failures:
16
- - rvm: rbx-2
17
18
  - rvm: ruby-head
18
19
  - rvm: jruby-head
data/Gemfile CHANGED
@@ -2,8 +2,6 @@ source 'https://rubygems.org'
2
2
 
3
3
  gemspec
4
4
 
5
- gem "async"
6
-
7
5
  group :development do
8
6
  gem "pry"
9
7
  end
@@ -21,11 +21,12 @@ Gem::Specification.new do |spec|
21
21
  spec.require_paths = ["lib"]
22
22
  spec.has_rdoc = "yard"
23
23
 
24
- spec.add_dependency("async", "~> 0.10")
24
+ spec.add_dependency("async-io", "~> 0.1")
25
25
 
26
- spec.add_development_dependency "process-daemon", "~> 1.0.0"
26
+ spec.add_development_dependency "async-rspec", "~> 1.0"
27
+ spec.add_development_dependency "process-daemon", "~> 1.0"
27
28
 
28
29
  spec.add_development_dependency "bundler", "~> 1.3"
29
- spec.add_development_dependency "rspec", "~> 3.4.0"
30
+ spec.add_development_dependency "rspec", "~> 3.6"
30
31
  spec.add_development_dependency "rake"
31
32
  end
@@ -19,8 +19,8 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'async'
22
- require 'async/tcp_socket'
23
- require 'async/udp_socket'
22
+ require 'async/io/tcp_socket'
23
+ require 'async/io/udp_socket'
24
24
 
25
25
  require_relative 'dns/version'
26
26
 
@@ -22,11 +22,16 @@ require_relative 'transport'
22
22
 
23
23
  module Async::DNS
24
24
  class GenericHandler
25
- def initialize(server)
25
+ def initialize(server, address)
26
26
  @server = server
27
+ @address = address
28
+
27
29
  @logger = @server.logger || Async.logger
28
30
  end
29
31
 
32
+ attr :server
33
+ attr :address
34
+
30
35
  def error_response(query = nil, code = Resolv::DNS::RCode::ServFail)
31
36
  # Encoding may fail, so we need to handle this particular case:
32
37
  server_failure = Resolv::DNS::Message::new(query ? query.id : 0)
@@ -61,27 +66,23 @@ module Async::DNS
61
66
  end
62
67
 
63
68
  # Handling incoming UDP requests, which are single data packets, and pass them on to the given server.
64
- class UDPHandler < GenericHandler
65
- def run(socket, reactor:)
66
- Async.logger.debug(self.class.name) {"-> Run on #{socket}..."}
67
-
68
- while true
69
- Async.logger.debug(self.class.name) {"-> socket.recvfrom"}
70
- input_data, (_, remote_port, remote_host) = socket.recvfrom(UDP_TRUNCATION_SIZE)
71
- Async.logger.debug(self.class.name) {"<- socket.recvfrom"}
72
-
73
- reactor.async do
74
- respond(socket, input_data, remote_host, remote_port)
69
+ class DatagramHandler < GenericHandler
70
+ def run(task: Async::Task.current)
71
+ @address.bind do |socket|
72
+ while true
73
+ Async.logger.debug(self.class.name) {"-> socket.recvfrom"}
74
+ input_data, remote_address = socket.recvmsg(UDP_TRUNCATION_SIZE)
75
+ Async.logger.debug(self.class.name) {"<- socket.recvfrom"}
76
+
77
+ task.async do
78
+ respond(socket, input_data, remote_address)
79
+ end
75
80
  end
76
81
  end
77
- ensure
78
- Async.logger.debug(self.class.name) {"<- Run ensure... #{$!}"}
79
82
  end
80
83
 
81
- def respond(socket, input_data, remote_host, remote_port)
82
- options = {peer: remote_host, port: remote_port, proto: :udp}
83
-
84
- response = process_query(input_data, options)
84
+ def respond(socket, input_data, remote_address)
85
+ response = process_query(input_data, remote_address: remote_address)
85
86
 
86
87
  output_data = response.encode
87
88
 
@@ -97,7 +98,7 @@ module Async::DNS
97
98
  output_data = truncation_error.encode
98
99
  end
99
100
 
100
- socket.send(output_data, 0, remote_host, remote_port)
101
+ socket.sendmsg(output_data, 0, remote_address)
101
102
  rescue IOError => error
102
103
  @logger.warn "<> UDP response failed: #{error.inspect}!"
103
104
  rescue EOFError => error
@@ -107,71 +108,19 @@ module Async::DNS
107
108
  end
108
109
  end
109
110
 
110
- class UDPSocketHandler < UDPHandler
111
- def initialize(server, socket)
112
- @socket = socket
113
-
114
- super(server)
115
- end
116
-
117
- attr :socket
118
-
119
- def run(reactor: Async::Task.current.reactor)
120
- reactor.async(self.socket) do |socket|
121
- super(socket, reactor: reactor)
122
- end
123
- end
124
- end
125
-
126
- class UDPServerHandler < UDPHandler
127
- def initialize(server, host, port)
128
- @host = host
129
- @port = port
130
-
131
- super(server)
132
- end
133
-
134
- attr :host
135
- attr :port
136
-
137
- def run(reactor: Async::Task.current.reactor)
138
- reactor.with(make_socket) do |socket|
139
- super(socket, reactor: reactor)
140
- end
141
- end
142
-
143
- private
144
-
145
- def make_socket
146
- family ||= Async::DNS::address_family(@host)
147
-
148
- socket = ::UDPSocket.new(family)
149
- socket.bind(@host, @port)
150
-
151
- return socket
152
- end
153
- end
154
-
155
- class TCPHandler < GenericHandler
156
- def run(socket, reactor:)
157
- Async.logger.debug(self.class.name) {"-> Run on #{socket}..."}
158
-
159
- reactor.with(socket.accept) do |client|
111
+ class StreamHandler < GenericHandler
112
+ def run(task: Async::Task.current)
113
+ @address.accept do |client, address|
160
114
  handle_connection(client)
161
- end while true
162
- ensure
163
- Async.logger.debug(self.class.name) {"<- Run ensure... #{$!}"}
115
+ end
164
116
  end
165
117
 
166
118
  def handle_connection(socket)
167
119
  context = Async::Task.current
168
120
 
169
- _, remote_port, remote_host = socket.io.peeraddr
170
- options = {peer: remote_host, port: remote_port, proto: :tcp}
171
-
172
121
  input_data = StreamTransport.read_chunk(socket)
173
122
 
174
- response = process_query(input_data, options)
123
+ response = process_query(input_data, remote_address: socket.remote_address)
175
124
 
176
125
  length = StreamTransport.write_message(socket, response)
177
126
 
@@ -186,44 +135,4 @@ module Async::DNS
186
135
  @logger.warn "<> Error: Could not decode incoming TCP data!"
187
136
  end
188
137
  end
189
-
190
- class TCPSocketHandler < TCPHandler
191
- def initialize(server, socket)
192
- @socket = socket
193
-
194
- super(server)
195
- end
196
-
197
- attr :socket
198
-
199
- def run(reactor: Async::Task.current.reactor)
200
- reactor.async(@socket) do |socket|
201
- super(socket, reactor: reactor)
202
- end
203
- end
204
- end
205
-
206
- class TCPServerHandler < TCPHandler
207
- def initialize(server, host, port)
208
- @host = host
209
- @port = port
210
-
211
- super(server)
212
- end
213
-
214
- attr :host
215
- attr :port
216
-
217
- def run(reactor: Async::Task.current.reactor)
218
- reactor.with(make_socket) do |socket|
219
- super(socket, reactor: reactor)
220
- end
221
- end
222
-
223
- private
224
-
225
- def make_socket
226
- ::TCPServer.new(@host, @port)
227
- end
228
- end
229
138
  end
@@ -33,7 +33,7 @@ module Async::DNS
33
33
  Message = ::Resolv::DNS::Message
34
34
  DecodeError = ::Resolv::DNS::DecodeError
35
35
 
36
- @@dump_bad_message = nil
36
+ @dump_bad_message = nil
37
37
 
38
38
  # Call this function with a path where bad messages will be saved. Any message that causes an exception to be thrown while decoding the binary will be saved in base64 for later inspection. The log file could grow quickly so be careful - not designed for long term use.
39
39
  def self.log_bad_messages!(log_path)
@@ -133,20 +133,19 @@ module Async::DNS
133
133
  end
134
134
 
135
135
  # Send the message to available servers. If no servers respond correctly, nil is returned. This result indicates a failure of the resolver to correctly contact any server and get a valid response.
136
- def dispatch_request(message)
136
+ def dispatch_request(message, task: Async::Task.current)
137
137
  request = Request.new(message, @servers)
138
- context = Async::Task.current
139
138
 
140
- request.each do |server|
141
- @logger.debug "[#{message.id}] Sending request #{message.question.inspect} to server #{server.inspect}" if @logger
139
+ request.each do |address|
140
+ @logger.debug "[#{message.id}] Sending request #{message.question.inspect} to address #{address.inspect}" if @logger
142
141
 
143
142
  begin
144
143
  response = nil
145
144
 
146
- context.timeout(@timeout) do
147
- @logger.debug "[#{message.id}] -> Try server #{server}" if @logger
148
- response = try_server(request, server)
149
- @logger.debug "[#{message.id}] <- Try server #{server} = #{response}" if @logger
145
+ task.timeout(@timeout) do
146
+ @logger.debug "[#{message.id}] -> Try address #{address}" if @logger
147
+ response = try_server(request, address)
148
+ @logger.debug "[#{message.id}] <- Try address #{address} = #{response}" if @logger
150
149
  end
151
150
 
152
151
  if valid_response(message, response)
@@ -158,8 +157,10 @@ module Async::DNS
158
157
  @logger.warn "[#{message.id}] Invalid response from network: #{$!}!" if @logger
159
158
  rescue DecodeError
160
159
  @logger.warn "[#{message.id}] Error while decoding data from network: #{$!}!" if @logger
161
- rescue IOError
160
+ rescue IOError, Errno::ECONNRESET
162
161
  @logger.warn "[#{message.id}] Error while reading from network: #{$!}!" if @logger
162
+ rescue EOFError
163
+ @logger.warn "[#{message.id}] Could not read complete response from network: #{$!}" if @logger
163
164
  end
164
165
  end
165
166
 
@@ -183,14 +184,14 @@ module Async::DNS
183
184
  end
184
185
  end
185
186
 
186
- def try_server(request, server)
187
- case server[0]
188
- when :udp
189
- try_udp_server(request, server[1], server[2])
190
- when :tcp
191
- try_tcp_server(request, server[1], server[2])
187
+ def try_server(request, address)
188
+ case address.type
189
+ when Socket::SOCK_DGRAM
190
+ try_datagram_server(request, address)
191
+ when Socket::SOCK_STREAM
192
+ try_stream_server(request, address)
192
193
  else
193
- raise InvalidProtocolError.new(server)
194
+ raise InvalidProtocolError.new(address)
194
195
  end
195
196
  end
196
197
 
@@ -208,34 +209,20 @@ module Async::DNS
208
209
  return false
209
210
  end
210
211
 
211
- def udp_socket(family)
212
- @udp_sockets[family] ||= UDPSocket.new(family)
213
- end
214
-
215
- def try_udp_server(request, host, port)
216
- context = Async::Task.current
217
-
218
- family = Async::DNS::address_family(host)
219
-
220
- context.with(UDPSocket.new(family)) do |socket|
221
- socket.send(request.packet, 0, host, port)
222
-
223
- data, (_, remote_port) = socket.recvfrom(UDP_TRUNCATION_SIZE)
224
- # Need to check host, otherwise security issue.
212
+ def try_datagram_server(request, address, task: Async::Task.current)
213
+ address.connect do |socket|
214
+ socket.sendmsg(request.packet, 0)
225
215
 
226
- # May indicate some kind of spoofing attack:
227
- if port != remote_port
228
- raise InvalidResponseError.new("Data was not received from correct remote port (#{port} != #{remote_port})")
229
- end
216
+ data, peer = socket.recvmsg(UDP_TRUNCATION_SIZE)
230
217
 
231
218
  return Async::DNS::decode_message(data)
232
219
  end
233
220
  end
234
221
 
235
- def try_tcp_server(request, host, port)
222
+ def try_stream_server(request, address)
236
223
  context = Async::Task.current
237
224
 
238
- context.with(TCPSocket.new(host, port)) do |socket|
225
+ address.connect do |socket|
239
226
  StreamTransport.write_chunk(socket, request.packet)
240
227
 
241
228
  input_data = StreamTransport.read_chunk(socket)
@@ -263,12 +250,7 @@ module Async::DNS
263
250
  attr :logger
264
251
 
265
252
  def each(&block)
266
- @servers.each do |server|
267
- # TODO: This seems odd...
268
- next if @packet.bytesize > UDP_TRUNCATION_SIZE
269
-
270
- yield server
271
- end
253
+ Async::IO::Address.each(@servers, &block)
272
254
  end
273
255
 
274
256
  def update_id!(id)
@@ -19,6 +19,7 @@
19
19
  # THE SOFTWARE.
20
20
 
21
21
  require 'async'
22
+ require 'async/io/address'
22
23
 
23
24
  require_relative 'transaction'
24
25
  require_relative 'logger'
@@ -107,9 +108,11 @@ module Async::DNS
107
108
 
108
109
  setup_handlers if @handlers.empty?
109
110
 
110
- Async::Reactor.run do
111
+ Async::Reactor.run do |task|
111
112
  @handlers.each do |handler|
112
- handler.run(*args)
113
+ task.async do
114
+ handler.run(*args)
115
+ end
113
116
  end
114
117
 
115
118
  fire(:start)
@@ -121,32 +124,16 @@ module Async::DNS
121
124
  def setup_handlers
122
125
  fire(:setup)
123
126
 
124
- # Setup server sockets
125
- @interfaces.each do |spec|
126
- if spec.is_a?(BasicSocket)
127
- spec.do_not_reverse_lookup
128
- protocol = spec.getsockopt(Socket::SOL_SOCKET, Socket::SO_TYPE).unpack("i")[0]
129
- ip = spec.local_address.ip_address
130
- port = spec.local_address.ip_port
131
-
132
- case protocol
133
- when Socket::SOCK_DGRAM
134
- @logger.info "<> Attaching to pre-existing UDP socket #{ip}:#{port}"
135
- @handlers << UDPSocketHandler.new(self, spec)
136
- when Socket::SOCK_STREAM
137
- @logger.info "<> Attaching to pre-existing TCP socket #{ip}:#{port}"
138
- @handlers << TCPSocketHandler.new(self, spec)
139
- else
140
- raise ArgumentError.new("Unknown socket protocol: #{protocol}")
141
- end
142
- elsif spec[0] == :udp
143
- @logger.info "<> Listening on #{spec.join(':')}"
144
- @handlers << UDPServerHandler.new(self, spec[1], spec[2])
145
- elsif spec[0] == :tcp
146
- @logger.info "<> Listening on #{spec.join(':')}"
147
- @handlers << TCPServerHandler.new(self, spec[1], spec[2])
127
+ Async::IO::Address.each(@interfaces) do |address|
128
+ case address.type
129
+ when Socket::SOCK_DGRAM
130
+ @logger.info "<> Listening for datagrams on #{address.inspect}"
131
+ @handlers << DatagramHandler.new(self, address)
132
+ when Socket::SOCK_STREAM
133
+ @logger.info "<> Listening for connections on #{address.inspect}"
134
+ @handlers << StreamHandler.new(self, address)
148
135
  else
149
- raise ArgumentError.new("Invalid connection specification: #{spec.inspect}")
136
+ raise ArgumentError.new("Don't know how to handle #{address}")
150
137
  end
151
138
  end
152
139
  end
@@ -44,7 +44,11 @@ module Async::DNS
44
44
 
45
45
  # First we need to read in the length of the packet
46
46
  while buffer.size < 2
47
- buffer.write socket.read(1)
47
+ if data = socket.read(1)
48
+ buffer.write data
49
+ else
50
+ raise EOFError, "Could not read message size!"
51
+ end
48
52
  end
49
53
 
50
54
  # Read in the length, the first two bytes:
@@ -55,7 +59,11 @@ module Async::DNS
55
59
  required = (2 + length) - buffer.size
56
60
 
57
61
  # Read precisely the required amount:
58
- buffer.write socket.read(required)
62
+ if data = socket.read(required)
63
+ buffer.write data
64
+ else
65
+ raise EOFError, "Could not read message data!"
66
+ end
59
67
  end
60
68
 
61
69
  return buffer.string.byteslice(2, length)
@@ -20,6 +20,6 @@
20
20
 
21
21
  module Async
22
22
  module DNS
23
- VERSION = '0.10.0'
23
+ VERSION = '0.12.0'
24
24
  end
25
25
  end
@@ -21,38 +21,40 @@
21
21
  require 'async/dns'
22
22
  require 'async/dns/system'
23
23
 
24
- describe Async::DNS::TCPServerHandler do
24
+ describe Async::DNS::StreamHandler do
25
+ include_context Async::RSpec::Reactor
26
+
25
27
  let(:server) {Async::DNS::Server.new}
26
- let(:host) {'127.0.0.1'}
27
- let(:port) {6665}
28
+ let(:address) {Async::IO::Address.tcp('127.0.0.1', 6666)}
28
29
 
29
- subject {described_class.new(server, host, port)}
30
+ subject {described_class.new(server, address)}
30
31
 
31
32
  it "can rebind port" do
32
33
  2.times do
33
- socket = subject.send(:make_socket)
34
- expect(socket).to_not be_closed
34
+ task = reactor.async do
35
+ subject.run
36
+ end
35
37
 
36
- socket.close
37
- expect(socket).to be_closed
38
+ task.stop
38
39
  end
39
40
  end
40
41
  end
41
42
 
42
- describe Async::DNS::UDPServerHandler do
43
+ describe Async::DNS::DatagramHandler do
44
+ include_context Async::RSpec::Reactor
45
+
43
46
  let(:server) {Async::DNS::Server.new}
44
- let(:host) {'127.0.0.1'}
45
- let(:port) {6665}
47
+ let(:address) {Async::IO::Address.udp('127.0.0.1', 6666)}
46
48
 
47
- subject {described_class.new(server, host, port)}
49
+ subject {described_class.new(server, address)}
48
50
 
49
51
  it "can rebind port" do
50
52
  2.times do
51
- socket = subject.send(:make_socket)
52
- expect(socket).to_not be_closed
53
+ task = reactor.async do
54
+ subject.run
55
+ end
53
56
 
54
- socket.close
55
- expect(socket).to be_closed
57
+ task.stop
56
58
  end
57
59
  end
58
60
  end
@@ -34,12 +34,12 @@ module Async::DNS::IPv6Spec
34
34
  end
35
35
  end
36
36
 
37
- describe Async::DNS::TCPSocketHandler do
37
+ describe Async::DNS::StreamHandler do
38
+ include_context Async::RSpec::Reactor
39
+
38
40
  let(:server_interfaces) {[[:tcp, '::', 2004]]}
39
41
  let(:server) {TestServer.new(listen: server_interfaces)}
40
42
 
41
- include_context "reactor"
42
-
43
43
  it "should connect to the server using TCP via IPv6" do
44
44
  task = server.run
45
45
 
@@ -55,12 +55,12 @@ module Async::DNS::IPv6Spec
55
55
  end
56
56
  end
57
57
 
58
- describe Async::DNS::UDPSocketHandler do
58
+ describe Async::DNS::DatagramHandler do
59
+ include_context Async::RSpec::Reactor
60
+
59
61
  let(:server_interfaces) {[[:udp, '::', 2006]]}
60
62
  let(:server) {TestServer.new(listen: server_interfaces)}
61
63
 
62
- include_context "reactor"
63
-
64
64
  it "should connect to the server using UDP via IPv6" do
65
65
  task = server.run
66
66
 
@@ -25,7 +25,7 @@ require 'async/dns/replace'
25
25
 
26
26
  module Async::DNS::ReplaceSpec
27
27
  describe Async::DNS::Replace do
28
- include_context "reactor"
28
+ include_context Async::RSpec::Reactor
29
29
 
30
30
  let(:default_resolver) {Async::DNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])}
31
31
 
@@ -81,7 +81,7 @@ module Async::DNS::ResolverPerformanceSpec
81
81
  require 'benchmark'
82
82
  end
83
83
 
84
- include_context "reactor"
84
+ include_context Async::RSpec::Reactor
85
85
 
86
86
  it 'should be faster than native resolver' do
87
87
  # Async.logger.level = Logger::ERROR
@@ -24,51 +24,39 @@ require 'async/dns'
24
24
 
25
25
  module Async::DNS::ResolverSpec
26
26
  describe Async::DNS::Resolver do
27
+ include_context Async::RSpec::Reactor
28
+
27
29
  class JunkUDPServer
28
- def initialize
29
- @socket = UDPSocket.new
30
- @socket.bind("0.0.0.0", 6060)
30
+ def initialize(server_address = nil)
31
+ @server_address = server_address || Addrinfo.udp('0.0.0.0', 6060)
31
32
  end
32
33
 
33
- def stop
34
- @task.stop
35
- @socket.close
36
- end
37
-
38
- def run(reactor: Async::Task.current.reactor)
39
- @task = reactor.async(@socket) do |socket|
40
- data, (_, port, host) = socket.recvfrom(1024)
41
- socket.send("Foobar", 0, host, port)
34
+ def run(task: Async::Task.current)
35
+ task.async do
36
+ Async::IO::Socket.bind(@server_address) do |socket|
37
+ while true
38
+ data, address = socket.recvfrom(1024)
39
+ socket.send("foobar", 0, address)
40
+ end
41
+ end
42
42
  end
43
43
  end
44
44
  end
45
45
 
46
46
  class JunkTCPServer
47
- def initialize
48
- @socket = TCPServer.new("0.0.0.0", 6060)
49
- end
50
-
51
- def stop
52
- @task.stop
53
- @socket.close
47
+ def initialize(server_address = nil)
48
+ @server_address = server_address || Addrinfo.tcp('0.0.0.0', 6060)
54
49
  end
55
-
56
- def run(reactor: Async::Task.current.reactor)
57
- # @logger.debug "Waiting for incoming TCP connections #{@socket.inspect}..."
58
- @task = reactor.async(@socket) do |socket|
59
- reactor.with(socket.accept) do |client|
60
- handle_connection(client)
61
- end while true
50
+
51
+ def run(task: Async::Task.current)
52
+ task.async do
53
+ Async::IO::Socket.accept(@server_address, backlog: 10) do |socket|
54
+ socket.write("f\0\0bar")
55
+ end
62
56
  end
63
57
  end
64
-
65
- def handle_connection(socket)
66
- socket.write("\0\0obar")
67
- end
68
58
  end
69
59
 
70
- include_context "reactor"
71
-
72
60
  it "should result in non-existent domain" do
73
61
  resolver = Async::DNS::Resolver.new([[:udp, "8.8.8.8", 53], [:tcp, "8.8.8.8", 53]])
74
62
 
@@ -103,7 +91,7 @@ module Async::DNS::ResolverSpec
103
91
  let(:udp_server) {JunkUDPServer.new}
104
92
 
105
93
  it "should fail with decode error from bad udp server" do
106
- udp_server.run
94
+ server = udp_server.run
107
95
 
108
96
  resolver = Async::DNS::Resolver.new([[:udp, "0.0.0.0", 6060]])
109
97
 
@@ -111,13 +99,13 @@ module Async::DNS::ResolverSpec
111
99
 
112
100
  expect(response).to be == nil
113
101
 
114
- udp_server.stop
102
+ server.stop
115
103
  end
116
104
 
117
105
  let(:tcp_server) {JunkTCPServer.new}
118
106
 
119
107
  it "should fail with decode error from bad tcp server" do
120
- tcp_server.run
108
+ server = tcp_server.run
121
109
 
122
110
  resolver = Async::DNS::Resolver.new([[:tcp, "0.0.0.0", 6060]])
123
111
 
@@ -125,7 +113,7 @@ module Async::DNS::ResolverSpec
125
113
 
126
114
  expect(response).to be == nil
127
115
 
128
- tcp_server.stop
116
+ server.stop
129
117
  end
130
118
 
131
119
  it "should return some IPv4 and IPv6 addresses" do
@@ -26,7 +26,7 @@ require 'process/daemon'
26
26
 
27
27
  module Async::DNS::ServerPerformanceSpec
28
28
  describe Async::DNS::Server do
29
- include_context "reactor"
29
+ include_context Async::RSpec::Reactor
30
30
 
31
31
  context 'benchmark' do
32
32
  class MillionServer < Async::DNS::Server
@@ -36,7 +36,7 @@ module Async::DNS::SlowServerSpec
36
36
  end
37
37
 
38
38
  describe "Async::DNS Slow Server" do
39
- include_context "reactor"
39
+ include_context Async::RSpec::Reactor
40
40
 
41
41
  let(:server_interfaces) {[[:udp, '0.0.0.0', 5330], [:tcp, '0.0.0.0', 5330]]}
42
42
  let(:server) {SlowServer.new(listen: server_interfaces)}
@@ -34,8 +34,8 @@ module Async::DNS::SocketSpec
34
34
  end
35
35
  end
36
36
 
37
- describe Async::DNS::TCPSocketHandler do
38
- include_context "reactor"
37
+ describe Async::DNS::StreamHandler do
38
+ include_context Async::RSpec::Reactor
39
39
 
40
40
  let(:server_interfaces) {[TCPServer.new('127.0.0.1', 2002)]}
41
41
  let(:server) {TestServer.new(listen: server_interfaces)}
@@ -48,11 +48,12 @@ module Async::DNS::SocketSpec
48
48
  expect(response.class).to be == Async::DNS::Message
49
49
 
50
50
  task.stop
51
+ server_interfaces.each(&:close)
51
52
  end
52
53
  end
53
54
 
54
- describe Async::DNS::UDPSocketHandler do
55
- include_context "reactor"
55
+ describe Async::DNS::DatagramHandler do
56
+ include_context Async::RSpec::Reactor
56
57
 
57
58
  let(:server_interfaces) {[UDPSocket.new.tap{|socket| socket.bind('127.0.0.1', 2002)}]}
58
59
  let(:server) {TestServer.new(listen: server_interfaces)}
@@ -65,6 +66,7 @@ module Async::DNS::SocketSpec
65
66
  expect(response.class).to be == Async::DNS::Message
66
67
 
67
68
  task.stop
69
+ server_interfaces.each(&:close)
68
70
  end
69
71
  end
70
72
  end
@@ -25,7 +25,7 @@ require 'async/dns/system'
25
25
 
26
26
  module Async::DNS::SystemSpec
27
27
  describe Async::DNS::System do
28
- include_context "reactor"
28
+ include_context Async::RSpec::Reactor
29
29
 
30
30
  it "should have at least one namesever" do
31
31
  expect(Async::DNS::System::nameservers.length).to be > 0
@@ -34,7 +34,7 @@ module Async::DNS::TransactionSpec
34
34
  let(:response) { Async::DNS::Message.new(0) }
35
35
  let(:resolver) { Async::DNS::Resolver.new([[:udp, '8.8.8.8', 53], [:tcp, '8.8.8.8', 53]])}
36
36
 
37
- include_context "reactor"
37
+ include_context Async::RSpec::Reactor
38
38
 
39
39
  it "should append an address" do
40
40
  transaction = Async::DNS::Transaction.new(server, query, question, IN::A, response)
@@ -40,7 +40,7 @@ module Async::DNS::TruncationSpec
40
40
  end
41
41
 
42
42
  describe "Async::DNS Truncation Server" do
43
- include_context "reactor"
43
+ include_context Async::RSpec::Reactor
44
44
 
45
45
  let(:server) {TestServer.new(listen: SERVER_PORTS)}
46
46
 
@@ -23,30 +23,8 @@ if ENV['COVERAGE'] || ENV['TRAVIS']
23
23
  end
24
24
 
25
25
  require "bundler/setup"
26
- require "pry"
26
+ require "async/rspec"
27
27
  require "async/dns"
28
- require "pp"
29
-
30
- RSpec.shared_context "reactor" do
31
- let(:reactor) {Async::Reactor.new}
32
-
33
- around(:each) do |example|
34
- result = nil
35
-
36
- reactor.run do
37
- result = example.run
38
-
39
- # Force the reactor to stop running if the result was an error.
40
- if result.is_a? Exception
41
- reactor.stop
42
- end
43
- end
44
-
45
- reactor.close
46
-
47
- result
48
- end
49
- end
50
28
 
51
29
  # abort "Warning, ulimit is too low!" if `ulimit -n`.to_i < 10000
52
30
 
metadata CHANGED
@@ -1,43 +1,57 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: async-dns
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.10.0
4
+ version: 0.12.0
5
5
  platform: ruby
6
6
  authors:
7
7
  - Samuel Williams
8
8
  autorequire:
9
9
  bindir: bin
10
10
  cert_chain: []
11
- date: 2017-04-09 00:00:00.000000000 Z
11
+ date: 2017-05-25 00:00:00.000000000 Z
12
12
  dependencies:
13
13
  - !ruby/object:Gem::Dependency
14
- name: async
14
+ name: async-io
15
15
  requirement: !ruby/object:Gem::Requirement
16
16
  requirements:
17
17
  - - "~>"
18
18
  - !ruby/object:Gem::Version
19
- version: '0.10'
19
+ version: '0.1'
20
20
  type: :runtime
21
21
  prerelease: false
22
22
  version_requirements: !ruby/object:Gem::Requirement
23
23
  requirements:
24
24
  - - "~>"
25
25
  - !ruby/object:Gem::Version
26
- version: '0.10'
26
+ version: '0.1'
27
+ - !ruby/object:Gem::Dependency
28
+ name: async-rspec
29
+ requirement: !ruby/object:Gem::Requirement
30
+ requirements:
31
+ - - "~>"
32
+ - !ruby/object:Gem::Version
33
+ version: '1.0'
34
+ type: :development
35
+ prerelease: false
36
+ version_requirements: !ruby/object:Gem::Requirement
37
+ requirements:
38
+ - - "~>"
39
+ - !ruby/object:Gem::Version
40
+ version: '1.0'
27
41
  - !ruby/object:Gem::Dependency
28
42
  name: process-daemon
29
43
  requirement: !ruby/object:Gem::Requirement
30
44
  requirements:
31
45
  - - "~>"
32
46
  - !ruby/object:Gem::Version
33
- version: 1.0.0
47
+ version: '1.0'
34
48
  type: :development
35
49
  prerelease: false
36
50
  version_requirements: !ruby/object:Gem::Requirement
37
51
  requirements:
38
52
  - - "~>"
39
53
  - !ruby/object:Gem::Version
40
- version: 1.0.0
54
+ version: '1.0'
41
55
  - !ruby/object:Gem::Dependency
42
56
  name: bundler
43
57
  requirement: !ruby/object:Gem::Requirement
@@ -58,14 +72,14 @@ dependencies:
58
72
  requirements:
59
73
  - - "~>"
60
74
  - !ruby/object:Gem::Version
61
- version: 3.4.0
75
+ version: '3.6'
62
76
  type: :development
63
77
  prerelease: false
64
78
  version_requirements: !ruby/object:Gem::Requirement
65
79
  requirements:
66
80
  - - "~>"
67
81
  - !ruby/object:Gem::Version
68
- version: 3.4.0
82
+ version: '3.6'
69
83
  - !ruby/object:Gem::Dependency
70
84
  name: rake
71
85
  requirement: !ruby/object:Gem::Requirement
@@ -88,6 +102,7 @@ executables: []
88
102
  extensions: []
89
103
  extra_rdoc_files: []
90
104
  files:
105
+ - ".gitignore"
91
106
  - ".rspec"
92
107
  - ".travis.yml"
93
108
  - Gemfile