arachni-reactor 0.1.0.beta5 → 0.1.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.
- checksums.yaml +4 -4
- data/CHANGELOG.md +6 -0
- data/README.md +3 -3
- data/lib/arachni/reactor.rb +54 -34
- data/lib/arachni/reactor/connection.rb +90 -57
- data/lib/arachni/reactor/connection/error.rb +1 -1
- data/lib/arachni/reactor/connection/tls.rb +75 -21
- data/lib/arachni/reactor/version.rb +1 -1
- data/spec/arachni/reactor/connection/tls_spec.rb +30 -17
- data/spec/arachni/reactor/connection_spec.rb +19 -3
- data/spec/support/helpers/utilities.rb +14 -0
- data/spec/support/lib/servers.rb +2 -2
- data/spec/support/servers/echo.rb +3 -3
- data/spec/support/servers/echo_tls.rb +2 -2
- data/spec/support/servers/echo_unix.rb +2 -2
- data/spec/support/servers/echo_unix_tls.rb +2 -2
- data/spec/support/shared/connection.rb +58 -140
- metadata +5 -5
checksums.yaml
CHANGED
|
@@ -1,7 +1,7 @@
|
|
|
1
1
|
---
|
|
2
2
|
SHA1:
|
|
3
|
-
metadata.gz:
|
|
4
|
-
data.tar.gz:
|
|
3
|
+
metadata.gz: d8f90922fd68d3df405cf0aa7537924db3f3c118
|
|
4
|
+
data.tar.gz: 5bd9e5042618276a83909b43879651d60f8e0538
|
|
5
5
|
SHA512:
|
|
6
|
-
metadata.gz:
|
|
7
|
-
data.tar.gz:
|
|
6
|
+
metadata.gz: ff7c11326a30b31030b95ac93cd7ee3e5c37ab6f7097bb6f9a4829354b13bc683d484e8243bb9d14e88b8248bd69481a9a43ac01d475a708e61199595ec4632b
|
|
7
|
+
data.tar.gz: f1563d0bafe856937029267327fa8c049b05a56122e8fa8dd5c1fd0b45bb7e9784f250eb8dfd4d6438d8b866cd402de4340b9382d5a304c204fd54552c4a389c
|
data/CHANGELOG.md
CHANGED
|
@@ -1,5 +1,11 @@
|
|
|
1
1
|
# ChangeLog
|
|
2
2
|
|
|
3
|
+
## Version 0.1.0
|
|
4
|
+
|
|
5
|
+
- Cleaned up connection handling structure for JRuby support.
|
|
6
|
+
- `Connection`
|
|
7
|
+
- `PeerInfo` now not included by default and only available for servers.
|
|
8
|
+
|
|
3
9
|
## Version 0.1.0.beta5 _(September 4, 2014)_
|
|
4
10
|
|
|
5
11
|
- `Tasks::OneOff#call`: Ensure that the task is marked as done even if an
|
data/README.md
CHANGED
|
@@ -3,7 +3,7 @@
|
|
|
3
3
|
<table>
|
|
4
4
|
<tr>
|
|
5
5
|
<th>Version</th>
|
|
6
|
-
<td>0.1.0
|
|
6
|
+
<td>0.1.0</td>
|
|
7
7
|
</tr>
|
|
8
8
|
<tr>
|
|
9
9
|
<th>Github page</th>
|
|
@@ -51,7 +51,7 @@ on network connections -- and less so on generic tasks.
|
|
|
51
51
|
- Rubies:
|
|
52
52
|
- MRI >= 1.9
|
|
53
53
|
- Rubinius
|
|
54
|
-
- JRuby
|
|
54
|
+
- JRuby
|
|
55
55
|
- Operating Systems:
|
|
56
56
|
- Linux
|
|
57
57
|
- OSX
|
|
@@ -63,7 +63,7 @@ For examples please see the `examples/` directory.
|
|
|
63
63
|
|
|
64
64
|
## Installation
|
|
65
65
|
|
|
66
|
-
gem install arachni-reactor
|
|
66
|
+
gem install arachni-reactor
|
|
67
67
|
|
|
68
68
|
## Running the Specs
|
|
69
69
|
|
data/lib/arachni/reactor.rb
CHANGED
|
@@ -199,10 +199,9 @@ class Reactor
|
|
|
199
199
|
begin
|
|
200
200
|
Connection::Error.translate do
|
|
201
201
|
socket = options[:unix_socket] ?
|
|
202
|
-
connect_unix( options[:unix_socket] ) :
|
|
203
|
-
connect_tcp( options[:host], options[:port] )
|
|
202
|
+
connect_unix( options[:unix_socket] ) : connect_tcp
|
|
204
203
|
|
|
205
|
-
connection.configure socket, :client
|
|
204
|
+
connection.configure options.merge( socket: socket, role: :client )
|
|
206
205
|
attach connection
|
|
207
206
|
end
|
|
208
207
|
rescue Connection::Error => e
|
|
@@ -266,7 +265,7 @@ class Reactor
|
|
|
266
265
|
listen_unix( options[:unix_socket] ) :
|
|
267
266
|
listen_tcp( options[:host], options[:port] )
|
|
268
267
|
|
|
269
|
-
server.configure socket, :server, server_handler
|
|
268
|
+
server.configure options.merge( socket: socket, role: :server, server_handler: server_handler )
|
|
270
269
|
attach server
|
|
271
270
|
end
|
|
272
271
|
rescue Connection::Error => e
|
|
@@ -500,7 +499,7 @@ class Reactor
|
|
|
500
499
|
|
|
501
500
|
schedule do
|
|
502
501
|
connection.reactor = self
|
|
503
|
-
@connections[connection.
|
|
502
|
+
@connections[connection.to_io] = connection
|
|
504
503
|
connection.on_attach
|
|
505
504
|
end
|
|
506
505
|
end
|
|
@@ -517,7 +516,7 @@ class Reactor
|
|
|
517
516
|
|
|
518
517
|
schedule do
|
|
519
518
|
connection.on_detach
|
|
520
|
-
@connections.delete connection.
|
|
519
|
+
@connections.delete connection.to_io
|
|
521
520
|
connection.reactor = nil
|
|
522
521
|
end
|
|
523
522
|
end
|
|
@@ -525,7 +524,7 @@ class Reactor
|
|
|
525
524
|
# @return [Bool]
|
|
526
525
|
# `true` if the connection is attached, `false` otherwise.
|
|
527
526
|
def attached?( connection )
|
|
528
|
-
@connections.include? connection.
|
|
527
|
+
@connections.include? connection.to_io
|
|
529
528
|
end
|
|
530
529
|
|
|
531
530
|
private
|
|
@@ -558,6 +557,13 @@ class Reactor
|
|
|
558
557
|
return
|
|
559
558
|
end
|
|
560
559
|
|
|
560
|
+
# Required for OSX as it connects immediately and then #select returns
|
|
561
|
+
# nothing as there's no activity, given that, OpenSSL doesn't get a chance
|
|
562
|
+
# to do its handshake so explicitly connect pending sockets, bypassing #select.
|
|
563
|
+
@connections.each do |_, connection|
|
|
564
|
+
connection._connect if !connection.connected?
|
|
565
|
+
end
|
|
566
|
+
|
|
561
567
|
# Get connections with available events - :read, :write, :error.
|
|
562
568
|
selected = select_connections
|
|
563
569
|
|
|
@@ -599,26 +605,13 @@ class Reactor
|
|
|
599
605
|
|
|
600
606
|
# @return [Socket]
|
|
601
607
|
# Connected socket.
|
|
602
|
-
def connect_tcp
|
|
608
|
+
def connect_tcp
|
|
603
609
|
socket = Socket.new(
|
|
604
610
|
Socket::Constants::AF_INET,
|
|
605
611
|
Socket::Constants::SOCK_STREAM,
|
|
606
612
|
Socket::Constants::IPPROTO_IP
|
|
607
613
|
)
|
|
608
614
|
socket.do_not_reverse_lookup = true
|
|
609
|
-
|
|
610
|
-
# JRuby throws java.nio.channels.NotYetConnectedException even after
|
|
611
|
-
# it returns the socket from Kernel.select, so wait for it to connect
|
|
612
|
-
# before moving on.
|
|
613
|
-
if self.class.jruby?
|
|
614
|
-
socket.connect( Socket.sockaddr_in( port, host ) )
|
|
615
|
-
else
|
|
616
|
-
begin
|
|
617
|
-
socket.connect_nonblock( Socket.sockaddr_in( port, host ) )
|
|
618
|
-
rescue IO::WaitReadable, IO::WaitWritable, Errno::EINPROGRESS
|
|
619
|
-
end
|
|
620
|
-
end
|
|
621
|
-
|
|
622
615
|
socket
|
|
623
616
|
end
|
|
624
617
|
|
|
@@ -650,43 +643,70 @@ class Reactor
|
|
|
650
643
|
# {Connection#has_outgoing_data? outgoing buffer).
|
|
651
644
|
# * `:error`
|
|
652
645
|
def select_connections
|
|
653
|
-
|
|
646
|
+
readables = read_sockets
|
|
647
|
+
|
|
648
|
+
selected_sockets =
|
|
654
649
|
begin
|
|
655
650
|
Connection::Error.translate do
|
|
656
651
|
select(
|
|
657
|
-
|
|
652
|
+
readables,
|
|
658
653
|
write_sockets,
|
|
659
|
-
|
|
654
|
+
all_sockets,
|
|
660
655
|
@select_timeout
|
|
661
656
|
)
|
|
662
657
|
end
|
|
663
|
-
rescue Connection::Error
|
|
658
|
+
rescue Connection::Error => e
|
|
659
|
+
nil
|
|
664
660
|
end
|
|
665
661
|
|
|
666
|
-
|
|
662
|
+
selected_sockets ||= [[],[],[]]
|
|
663
|
+
|
|
664
|
+
# SSL sockets maintain their own buffer whose state can't be checked by
|
|
665
|
+
# Kernel.select, leading to cases where the SSL buffer isn't empty,
|
|
666
|
+
# even though Kernel.select says that there's nothing to read.
|
|
667
|
+
#
|
|
668
|
+
# So force a read for SSL sockets to cover all our bases.
|
|
669
|
+
#
|
|
670
|
+
# This is apparent especially on JRuby.
|
|
671
|
+
(readables - selected_sockets[0]).each do |socket|
|
|
672
|
+
next if !socket.is_a?( OpenSSL::SSL::SSLSocket )
|
|
673
|
+
selected_sockets[0] << socket
|
|
674
|
+
end
|
|
675
|
+
|
|
676
|
+
if selected_sockets[0].empty? && selected_sockets[1].empty? &&
|
|
677
|
+
selected_sockets[2].empty?
|
|
678
|
+
return {}
|
|
679
|
+
end
|
|
667
680
|
|
|
668
681
|
{
|
|
669
682
|
# Since these will be processed in order, it's better have the write
|
|
670
683
|
# ones first to flush the buffers ASAP.
|
|
671
|
-
write:
|
|
672
|
-
read:
|
|
673
|
-
error:
|
|
684
|
+
write: connections_from_sockets( selected_sockets[1] ),
|
|
685
|
+
read: connections_from_sockets( selected_sockets[0] ),
|
|
686
|
+
error: connections_from_sockets( selected_sockets[2] )
|
|
674
687
|
}
|
|
675
688
|
end
|
|
676
689
|
|
|
677
690
|
# @return [Array<Socket>]
|
|
678
691
|
# Sockets of all connections, we want to be ready to read at any time.
|
|
679
692
|
def read_sockets
|
|
680
|
-
@connections.
|
|
693
|
+
@connections.map do |_, connection|
|
|
694
|
+
next if !connection.listener? && !connection.connected?
|
|
695
|
+
connection.socket
|
|
696
|
+
end.compact
|
|
697
|
+
end
|
|
698
|
+
|
|
699
|
+
def all_sockets
|
|
700
|
+
@connections.values.map(&:socket)
|
|
681
701
|
end
|
|
682
702
|
|
|
683
703
|
# @return [Array<Socket>]
|
|
684
704
|
# Sockets of connections with
|
|
685
705
|
# {Connection#has_outgoing_data? outgoing data}.
|
|
686
706
|
def write_sockets
|
|
687
|
-
@connections.map do |
|
|
688
|
-
next if !connection.has_outgoing_data?
|
|
689
|
-
socket
|
|
707
|
+
@connections.map do |_, connection|
|
|
708
|
+
next if connection.connected? && !connection.has_outgoing_data?
|
|
709
|
+
connection.socket
|
|
690
710
|
end.compact
|
|
691
711
|
end
|
|
692
712
|
|
|
@@ -695,7 +715,7 @@ class Reactor
|
|
|
695
715
|
end
|
|
696
716
|
|
|
697
717
|
def connection_from_socket( socket )
|
|
698
|
-
@connections[socket]
|
|
718
|
+
@connections[socket.to_io]
|
|
699
719
|
end
|
|
700
720
|
|
|
701
721
|
end
|
|
@@ -7,8 +7,8 @@
|
|
|
7
7
|
=end
|
|
8
8
|
|
|
9
9
|
require_relative 'connection/error'
|
|
10
|
-
require_relative 'connection/peer_info'
|
|
11
10
|
require_relative 'connection/callbacks'
|
|
11
|
+
require_relative 'connection/peer_info'
|
|
12
12
|
require_relative 'connection/tls'
|
|
13
13
|
|
|
14
14
|
module Arachni
|
|
@@ -16,7 +16,6 @@ class Reactor
|
|
|
16
16
|
|
|
17
17
|
# @author Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
|
|
18
18
|
class Connection
|
|
19
|
-
include PeerInfo
|
|
20
19
|
include Callbacks
|
|
21
20
|
|
|
22
21
|
# Maximum amount of data to be written or read at a time.
|
|
@@ -176,6 +175,92 @@ class Connection
|
|
|
176
175
|
nil
|
|
177
176
|
end
|
|
178
177
|
|
|
178
|
+
# Accepts a new client connection.
|
|
179
|
+
#
|
|
180
|
+
# @return [Connection, nil]
|
|
181
|
+
# New connection or `nil` if the socket isn't ready to accept new
|
|
182
|
+
# connections yet.
|
|
183
|
+
#
|
|
184
|
+
# @private
|
|
185
|
+
def accept
|
|
186
|
+
return if !(accepted = socket_accept)
|
|
187
|
+
|
|
188
|
+
connection = @server_handler.call
|
|
189
|
+
connection.configure socket: accepted, role: :server
|
|
190
|
+
@reactor.attach connection
|
|
191
|
+
connection
|
|
192
|
+
end
|
|
193
|
+
|
|
194
|
+
# @param [Socket] socket
|
|
195
|
+
# Ruby `Socket` associated with this connection.
|
|
196
|
+
# @param [Symbol] role
|
|
197
|
+
# `:server` or `:client`.
|
|
198
|
+
# @param [Block] server_handler
|
|
199
|
+
# Block that generates a handler as specified in {Reactor#listen}.
|
|
200
|
+
#
|
|
201
|
+
# @private
|
|
202
|
+
def configure( options = {} )
|
|
203
|
+
@socket = options[:socket]
|
|
204
|
+
@role = options[:role]
|
|
205
|
+
@host = options[:host]
|
|
206
|
+
@port = options[:port]
|
|
207
|
+
@server_handler = options[:server_handler]
|
|
208
|
+
|
|
209
|
+
# If we're a server without a handler then we're an accepted connection.
|
|
210
|
+
if unix? || role == :server
|
|
211
|
+
@connected = true
|
|
212
|
+
on_connect
|
|
213
|
+
end
|
|
214
|
+
|
|
215
|
+
nil
|
|
216
|
+
end
|
|
217
|
+
|
|
218
|
+
def connected?
|
|
219
|
+
!!@connected
|
|
220
|
+
end
|
|
221
|
+
|
|
222
|
+
# @private
|
|
223
|
+
def _connect
|
|
224
|
+
return true if unix? || connected?
|
|
225
|
+
|
|
226
|
+
begin
|
|
227
|
+
Error.translate do
|
|
228
|
+
socket.connect_nonblock( Socket.sockaddr_in( @port, @host ) )
|
|
229
|
+
end
|
|
230
|
+
# Already connected. :)
|
|
231
|
+
rescue Errno::EISCONN
|
|
232
|
+
end
|
|
233
|
+
|
|
234
|
+
@connected = true
|
|
235
|
+
on_connect
|
|
236
|
+
|
|
237
|
+
true
|
|
238
|
+
rescue IO::WaitReadable, IO::WaitWritable, Errno::EINPROGRESS
|
|
239
|
+
rescue Error => e
|
|
240
|
+
close e
|
|
241
|
+
end
|
|
242
|
+
|
|
243
|
+
# @note If this is a server {#listener?} it will delegate to {#accept}.
|
|
244
|
+
# @note If this is a normal socket it will read {BLOCK_SIZE} amount of data.
|
|
245
|
+
# and pass it to {#on_read}.
|
|
246
|
+
#
|
|
247
|
+
# Processes a `read` event for this connection.
|
|
248
|
+
#
|
|
249
|
+
# @private
|
|
250
|
+
def _read
|
|
251
|
+
return _connect if !listener? && !connected?
|
|
252
|
+
return accept if listener?
|
|
253
|
+
|
|
254
|
+
Error.translate do
|
|
255
|
+
on_read @socket.read_nonblock( BLOCK_SIZE )
|
|
256
|
+
end
|
|
257
|
+
|
|
258
|
+
# Not ready to read or write yet, we'll catch it on future Reactor ticks.
|
|
259
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
|
260
|
+
rescue Error => e
|
|
261
|
+
close e
|
|
262
|
+
end
|
|
263
|
+
|
|
179
264
|
# @note Will call {#on_write} every time any of the buffer is consumed,
|
|
180
265
|
# can be multiple times when performing partial writes.
|
|
181
266
|
# @note Will call {#on_flush} once all of the buffer has been consumed.
|
|
@@ -190,12 +275,14 @@ class Connection
|
|
|
190
275
|
#
|
|
191
276
|
# @private
|
|
192
277
|
def _write
|
|
278
|
+
return _connect if !connected?
|
|
279
|
+
|
|
193
280
|
chunk = write_buffer.slice( 0, BLOCK_SIZE )
|
|
194
281
|
total_written = 0
|
|
195
282
|
|
|
196
283
|
begin
|
|
197
284
|
Error.translate do
|
|
198
|
-
# Send out the
|
|
285
|
+
# Send out the chunk, **all** of it, or at least try to.
|
|
199
286
|
loop do
|
|
200
287
|
total_written += written = @socket.write_nonblock( chunk )
|
|
201
288
|
write_buffer.slice!( 0, written )
|
|
@@ -222,60 +309,6 @@ class Connection
|
|
|
222
309
|
close e
|
|
223
310
|
end
|
|
224
311
|
|
|
225
|
-
# @note If this is a server {#listener?} it will delegate to {#accept}.
|
|
226
|
-
# @note If this is a normal socket it will read {BLOCK_SIZE} amount of data.
|
|
227
|
-
# and pass it to {#on_read}.
|
|
228
|
-
#
|
|
229
|
-
# Processes a `read` event for this connection.
|
|
230
|
-
#
|
|
231
|
-
# @private
|
|
232
|
-
def _read
|
|
233
|
-
return accept if listener?
|
|
234
|
-
|
|
235
|
-
Error.translate do
|
|
236
|
-
on_read @socket.read_nonblock( BLOCK_SIZE )
|
|
237
|
-
end
|
|
238
|
-
|
|
239
|
-
# Not ready to read or write yet, we'll catch it on future Reactor ticks.
|
|
240
|
-
rescue IO::WaitReadable, IO::WaitWritable
|
|
241
|
-
rescue Error => e
|
|
242
|
-
close e
|
|
243
|
-
end
|
|
244
|
-
|
|
245
|
-
# Accepts a new client connection.
|
|
246
|
-
#
|
|
247
|
-
# @return [Connection, nil]
|
|
248
|
-
# New connection or `nil` if the socket isn't ready to accept new
|
|
249
|
-
# connections yet.
|
|
250
|
-
#
|
|
251
|
-
# @private
|
|
252
|
-
def accept
|
|
253
|
-
return if !(accepted = socket_accept)
|
|
254
|
-
|
|
255
|
-
connection = @server_handler.call
|
|
256
|
-
connection.configure accepted, :server
|
|
257
|
-
@reactor.attach connection
|
|
258
|
-
connection
|
|
259
|
-
end
|
|
260
|
-
|
|
261
|
-
# @param [Socket] socket
|
|
262
|
-
# Ruby `Socket` associated with this connection.
|
|
263
|
-
# @param [Symbol] role
|
|
264
|
-
# `:server` or `:client`.
|
|
265
|
-
# @param [Block] server_handler
|
|
266
|
-
# Block that generates a handler as specified in {Reactor#listen}.
|
|
267
|
-
#
|
|
268
|
-
# @private
|
|
269
|
-
def configure( socket, role, server_handler = nil )
|
|
270
|
-
@socket = socket
|
|
271
|
-
@role = role
|
|
272
|
-
@server_handler = server_handler
|
|
273
|
-
|
|
274
|
-
on_connect
|
|
275
|
-
|
|
276
|
-
nil
|
|
277
|
-
end
|
|
278
|
-
|
|
279
312
|
private
|
|
280
313
|
|
|
281
314
|
def write_buffer
|
|
@@ -51,7 +51,7 @@ class Error < Arachni::Reactor::Error
|
|
|
51
51
|
# aren't any specific exceptions for these.
|
|
52
52
|
#
|
|
53
53
|
# Why make things easy and clean, right?
|
|
54
|
-
rescue OpenSSL::OpenSSLError => e
|
|
54
|
+
rescue OpenSSL::SSL::SSLError, OpenSSL::OpenSSLError => e
|
|
55
55
|
raise_with_proper_backtrace( e, SSL )
|
|
56
56
|
end
|
|
57
57
|
|
|
@@ -62,17 +62,78 @@ module TLS
|
|
|
62
62
|
@socket = OpenSSL::SSL::SSLSocket.new( @socket, @ssl_context )
|
|
63
63
|
@socket.sync_close = true
|
|
64
64
|
|
|
65
|
-
|
|
66
|
-
|
|
67
|
-
|
|
68
|
-
|
|
65
|
+
# We've switched to SSL, a connection needs to be re-established
|
|
66
|
+
# via the SSL handshake.
|
|
67
|
+
@connected = false
|
|
68
|
+
|
|
69
|
+
_connect if unix?
|
|
69
70
|
end
|
|
70
71
|
|
|
71
72
|
@socket
|
|
72
73
|
end
|
|
73
74
|
|
|
75
|
+
# Performs an SSL handshake in addition to a plaintext connect operation.
|
|
76
|
+
#
|
|
77
|
+
# @private
|
|
78
|
+
def _connect
|
|
79
|
+
return if @ssl_connected
|
|
80
|
+
|
|
81
|
+
Error.translate do
|
|
82
|
+
@plaintext_connected ||= super
|
|
83
|
+
return if !@plaintext_connected
|
|
84
|
+
|
|
85
|
+
# Mark the connection as not connected due to the pending SSL handshake.
|
|
86
|
+
@connected = false
|
|
87
|
+
|
|
88
|
+
@socket.connect_nonblock
|
|
89
|
+
@ssl_connected = @connected = true
|
|
90
|
+
end
|
|
91
|
+
rescue IO::WaitReadable, IO::WaitWritable, Errno::EINPROGRESS
|
|
92
|
+
rescue Error => e
|
|
93
|
+
close e
|
|
94
|
+
end
|
|
95
|
+
|
|
96
|
+
# First checks if there's a pending SSL #accept operation when this
|
|
97
|
+
# connection is a server handler which has been passed an accepted
|
|
98
|
+
# plaintext connection.
|
|
99
|
+
#
|
|
100
|
+
# @private
|
|
101
|
+
def _write( *args )
|
|
102
|
+
return ssl_accept if accept?
|
|
103
|
+
|
|
104
|
+
super( *args )
|
|
105
|
+
end
|
|
106
|
+
|
|
107
|
+
# First checks if there's a pending SSL #accept operation when this
|
|
108
|
+
# connection is a server handler which has been passed an accepted
|
|
109
|
+
# plaintext connection.
|
|
110
|
+
#
|
|
111
|
+
# @private
|
|
112
|
+
def _read
|
|
113
|
+
return ssl_accept if accept?
|
|
114
|
+
|
|
115
|
+
super
|
|
116
|
+
end
|
|
117
|
+
|
|
74
118
|
private
|
|
75
119
|
|
|
120
|
+
def ssl_accept
|
|
121
|
+
Error.translate do
|
|
122
|
+
@accepted = !!@socket.accept_nonblock
|
|
123
|
+
end
|
|
124
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
|
125
|
+
rescue Error => e
|
|
126
|
+
close e
|
|
127
|
+
false
|
|
128
|
+
end
|
|
129
|
+
|
|
130
|
+
def accept?
|
|
131
|
+
return false if @accepted
|
|
132
|
+
return false if role != :server || !@socket.is_a?( OpenSSL::SSL::SSLSocket )
|
|
133
|
+
|
|
134
|
+
true
|
|
135
|
+
end
|
|
136
|
+
|
|
76
137
|
# Accepts a new SSL client connection.
|
|
77
138
|
#
|
|
78
139
|
# @return [OpenSSL::SSL::SSLSocket, nil]
|
|
@@ -81,26 +142,19 @@ module TLS
|
|
|
81
142
|
#
|
|
82
143
|
# @private
|
|
83
144
|
def socket_accept
|
|
84
|
-
|
|
85
|
-
begin
|
|
145
|
+
Error.translate do
|
|
86
146
|
socket = to_io.accept_nonblock
|
|
87
|
-
rescue IO::WaitReadable, IO::WaitWritable
|
|
88
|
-
return
|
|
89
|
-
end
|
|
90
|
-
|
|
91
|
-
socket = OpenSSL::SSL::SSLSocket.new(
|
|
92
|
-
socket,
|
|
93
|
-
@ssl_context
|
|
94
|
-
)
|
|
95
|
-
socket.sync_close = true
|
|
96
147
|
|
|
97
|
-
|
|
98
|
-
|
|
99
|
-
|
|
148
|
+
ssl_socket = OpenSSL::SSL::SSLSocket.new(
|
|
149
|
+
socket,
|
|
150
|
+
@ssl_context
|
|
151
|
+
)
|
|
152
|
+
ssl_socket.sync_close = true
|
|
153
|
+
ssl_socket
|
|
100
154
|
end
|
|
101
|
-
|
|
102
|
-
|
|
103
|
-
|
|
155
|
+
rescue IO::WaitReadable, IO::WaitWritable
|
|
156
|
+
rescue Error => e
|
|
157
|
+
close e
|
|
104
158
|
end
|
|
105
159
|
|
|
106
160
|
end
|
|
@@ -43,16 +43,32 @@ describe Arachni::Reactor::Connection::TLS do
|
|
|
43
43
|
end
|
|
44
44
|
end
|
|
45
45
|
|
|
46
|
+
before :each do
|
|
47
|
+
@accept_q = Queue.new
|
|
48
|
+
@accepted = nil
|
|
49
|
+
end
|
|
50
|
+
|
|
46
51
|
let(:unix_socket) { unix_connect( @unix_socket ) }
|
|
47
52
|
let(:unix_server_socket) { unix_server( port_to_socket( Servers.available_port ) ) }
|
|
48
53
|
|
|
49
|
-
let(:echo_client) {
|
|
54
|
+
let(:echo_client) { tcp_socket }
|
|
50
55
|
let(:echo_client_handler) { EchoClientTLS.new }
|
|
51
56
|
|
|
52
57
|
let(:peer_client_socket) { tcp_ssl_connect( host, port ) }
|
|
53
|
-
let(:peer_server_socket)
|
|
58
|
+
let(:peer_server_socket) do
|
|
59
|
+
s = tcp_ssl_server( host, port )
|
|
60
|
+
Thread.new do
|
|
61
|
+
begin
|
|
62
|
+
@accept_q << s.accept
|
|
63
|
+
rescue => e
|
|
64
|
+
ap e
|
|
65
|
+
end
|
|
66
|
+
end
|
|
67
|
+
s
|
|
68
|
+
end
|
|
69
|
+
let(:accepted) { @accepted ||= @accept_q.pop }
|
|
54
70
|
|
|
55
|
-
let(:client_socket) {
|
|
71
|
+
let(:client_socket) { tcp_socket }
|
|
56
72
|
let(:server_socket) { tcp_server( host, port ) }
|
|
57
73
|
|
|
58
74
|
let(:connection) { TLSHandler.new }
|
|
@@ -244,7 +260,15 @@ describe Arachni::Reactor::Connection::TLS do
|
|
|
244
260
|
|
|
245
261
|
context 'when connecting to a server' do
|
|
246
262
|
let(:server) do
|
|
247
|
-
tcp_ssl_server( host, port, server_ssl_options )
|
|
263
|
+
s = tcp_ssl_server( host, port, server_ssl_options )
|
|
264
|
+
Thread.new do
|
|
265
|
+
begin
|
|
266
|
+
@accept_q << s.accept
|
|
267
|
+
rescue => e
|
|
268
|
+
# ap e
|
|
269
|
+
end
|
|
270
|
+
end
|
|
271
|
+
s
|
|
248
272
|
end
|
|
249
273
|
|
|
250
274
|
before :each do
|
|
@@ -258,9 +282,7 @@ describe Arachni::Reactor::Connection::TLS do
|
|
|
258
282
|
it 'connects successfully' do
|
|
259
283
|
received = nil
|
|
260
284
|
Thread.new do
|
|
261
|
-
|
|
262
|
-
received = s.gets
|
|
263
|
-
|
|
285
|
+
received = accepted.gets
|
|
264
286
|
reactor.stop
|
|
265
287
|
end
|
|
266
288
|
|
|
@@ -279,10 +301,6 @@ describe Arachni::Reactor::Connection::TLS do
|
|
|
279
301
|
|
|
280
302
|
context 'and no options have been provided' do
|
|
281
303
|
it "passes #{Arachni::Reactor::Connection::Error} to #on_error" do
|
|
282
|
-
Thread.new do
|
|
283
|
-
server.accept
|
|
284
|
-
end
|
|
285
|
-
|
|
286
304
|
connection = nil
|
|
287
305
|
reactor.run do
|
|
288
306
|
connection = reactor.connect( host, port, TLSHandler )
|
|
@@ -297,8 +315,7 @@ describe Arachni::Reactor::Connection::TLS do
|
|
|
297
315
|
it 'connects successfully' do
|
|
298
316
|
received = nil
|
|
299
317
|
t = Thread.new do
|
|
300
|
-
|
|
301
|
-
received = s.gets
|
|
318
|
+
received = accepted.gets
|
|
302
319
|
reactor.stop
|
|
303
320
|
end
|
|
304
321
|
|
|
@@ -313,10 +330,6 @@ describe Arachni::Reactor::Connection::TLS do
|
|
|
313
330
|
|
|
314
331
|
context 'and are invalid' do
|
|
315
332
|
it "passes #{Arachni::Reactor::Connection::Error} to #on_error" do
|
|
316
|
-
Thread.new do
|
|
317
|
-
server.accept
|
|
318
|
-
end
|
|
319
|
-
|
|
320
333
|
connection = nil
|
|
321
334
|
reactor.run do
|
|
322
335
|
connection = reactor.connect( host, port, TLSHandler, client_invalid_ssl_options )
|
|
@@ -39,16 +39,32 @@ describe Arachni::Reactor::Connection do
|
|
|
39
39
|
end
|
|
40
40
|
end
|
|
41
41
|
|
|
42
|
+
before :each do
|
|
43
|
+
@accept_q = Queue.new
|
|
44
|
+
@accepted = nil
|
|
45
|
+
end
|
|
46
|
+
|
|
42
47
|
let(:unix_socket) { unix_connect( @unix_socket ) }
|
|
43
48
|
let(:unix_server_socket) { unix_server( port_to_socket( Servers.available_port ) ) }
|
|
44
49
|
|
|
45
|
-
let(:echo_client) {
|
|
50
|
+
let(:echo_client) { tcp_socket }
|
|
46
51
|
let(:echo_client_handler) { EchoClient.new }
|
|
47
52
|
|
|
48
53
|
let(:peer_client_socket) { tcp_connect( host, port ) }
|
|
49
|
-
let(:peer_server_socket)
|
|
54
|
+
let(:peer_server_socket) do
|
|
55
|
+
s = tcp_server( host, port )
|
|
56
|
+
Thread.new do
|
|
57
|
+
begin
|
|
58
|
+
@accept_q << s.accept
|
|
59
|
+
rescue => e
|
|
60
|
+
ap e
|
|
61
|
+
end
|
|
62
|
+
end
|
|
63
|
+
s
|
|
64
|
+
end
|
|
65
|
+
let(:accepted) { @accepted ||= @accept_q.pop }
|
|
50
66
|
|
|
51
|
-
let(:client_socket) {
|
|
67
|
+
let(:client_socket) { tcp_socket }
|
|
52
68
|
let(:server_socket) { tcp_server( host, port ) }
|
|
53
69
|
|
|
54
70
|
let(:connection) { Handler.new }
|
|
@@ -17,6 +17,16 @@ def tcp_connect( host, port )
|
|
|
17
17
|
TCPSocket.new( host, port )
|
|
18
18
|
end
|
|
19
19
|
|
|
20
|
+
def tcp_socket
|
|
21
|
+
socket = Socket.new(
|
|
22
|
+
Socket::Constants::AF_INET,
|
|
23
|
+
Socket::Constants::SOCK_STREAM,
|
|
24
|
+
Socket::Constants::IPPROTO_IP
|
|
25
|
+
)
|
|
26
|
+
socket.do_not_reverse_lookup = true
|
|
27
|
+
socket
|
|
28
|
+
end
|
|
29
|
+
|
|
20
30
|
def tcp_write( host, port, data )
|
|
21
31
|
s = tcp_connect( host, port )
|
|
22
32
|
s.write data
|
|
@@ -45,6 +55,10 @@ def tcp_server( host, port )
|
|
|
45
55
|
TCPServer.new( host, port )
|
|
46
56
|
end
|
|
47
57
|
|
|
58
|
+
def tcp_ssl_socket( host, port, options = {} )
|
|
59
|
+
convert_client_to_ssl( tcp_socket, options )
|
|
60
|
+
end
|
|
61
|
+
|
|
48
62
|
def tcp_ssl_connect( host, port, options = {} )
|
|
49
63
|
convert_client_to_ssl( tcp_connect( host, port ), options )
|
|
50
64
|
end
|
data/spec/support/lib/servers.rb
CHANGED
|
@@ -26,7 +26,7 @@ class Servers
|
|
|
26
26
|
return [host_for(name), port_for(name)] if server_info[:pid] && up?( name )
|
|
27
27
|
|
|
28
28
|
server_info[:pid] = Process.spawn(
|
|
29
|
-
|
|
29
|
+
RbConfig.ruby, RUNNER, server_info[:path], '-p', server_info[:port].to_s,
|
|
30
30
|
'-o', host_for( name )
|
|
31
31
|
)
|
|
32
32
|
|
|
@@ -77,7 +77,7 @@ class Servers
|
|
|
77
77
|
return if !server_info[:pid]
|
|
78
78
|
|
|
79
79
|
begin
|
|
80
|
-
Process.kill( 'KILL', server_info[:pid] ) while sleep 0.1
|
|
80
|
+
Process.kill( Gem.win_platform? ? 'QUIT' : 'KILL', server_info[:pid] ) while sleep 0.1
|
|
81
81
|
rescue Errno::ESRCH
|
|
82
82
|
server_info.delete(:pid)
|
|
83
83
|
|
|
@@ -4,10 +4,10 @@ loop do
|
|
|
4
4
|
Thread.new server.accept do |socket|
|
|
5
5
|
begin
|
|
6
6
|
loop do
|
|
7
|
-
next if
|
|
8
|
-
socket.write(
|
|
7
|
+
next if (data = socket.gets).to_s.empty?
|
|
8
|
+
socket.write( data )
|
|
9
9
|
end
|
|
10
|
-
rescue EOFError, Errno::EPIPE
|
|
10
|
+
rescue EOFError, Errno::EPIPE, Errno::ECONNRESET
|
|
11
11
|
socket.close
|
|
12
12
|
end
|
|
13
13
|
end
|
|
@@ -16,117 +16,28 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
16
16
|
let(:data) { 'b' * 5 * block_size }
|
|
17
17
|
let(:configured) do
|
|
18
18
|
connection.reactor = reactor
|
|
19
|
-
connection.configure
|
|
20
|
-
|
|
21
|
-
|
|
22
|
-
|
|
23
|
-
|
|
24
|
-
|
|
25
|
-
|
|
26
|
-
|
|
27
|
-
|
|
28
|
-
|
|
29
|
-
|
|
30
|
-
|
|
31
|
-
|
|
32
|
-
|
|
33
|
-
|
|
34
|
-
|
|
35
|
-
Thread.new do
|
|
36
|
-
s = s.accept
|
|
37
|
-
end
|
|
38
|
-
|
|
39
|
-
IO.select( nil, [configured.socket] )
|
|
40
|
-
|
|
41
|
-
info = {}
|
|
42
|
-
info[:protocol], info[:port], info[:hostname], info[:ip_address] = s.to_io.addr
|
|
43
|
-
configured.peer_address_info.should == info
|
|
44
|
-
|
|
45
|
-
info = {}
|
|
46
|
-
info[:protocol], info[:port], info[:hostname], info[:ip_address] = s.to_io.addr(false)
|
|
47
|
-
configured.peer_address_info(false).should == info
|
|
48
|
-
|
|
49
|
-
info = {}
|
|
50
|
-
info[:protocol], info[:port], info[:hostname], info[:ip_address] = s.to_io.addr(true)
|
|
51
|
-
configured.peer_address_info(true).should == info
|
|
52
|
-
end
|
|
53
|
-
end
|
|
54
|
-
|
|
55
|
-
context 'when using UNIX-domain socket',
|
|
56
|
-
if: Arachni::Reactor.supports_unix_sockets? do
|
|
57
|
-
|
|
58
|
-
let(:connection) { echo_client_handler }
|
|
59
|
-
let(:role) { :client }
|
|
60
|
-
let(:socket) { unix_socket }
|
|
61
|
-
|
|
62
|
-
it 'returns socket information' do
|
|
63
|
-
configured
|
|
64
|
-
|
|
65
|
-
IO.select( nil, [configured.socket] )
|
|
66
|
-
|
|
67
|
-
info = {}
|
|
68
|
-
info[:protocol], info[:path] = 'AF_UNIX', socket.path
|
|
69
|
-
configured.peer_address_info.should == info
|
|
70
|
-
end
|
|
71
|
-
end
|
|
72
|
-
end
|
|
73
|
-
|
|
74
|
-
describe '#peer_hostname' do
|
|
75
|
-
let(:connection) { echo_client_handler }
|
|
76
|
-
let(:role) { :client }
|
|
77
|
-
let(:socket) { client_socket }
|
|
78
|
-
|
|
79
|
-
it 'returns the peer hostname' do
|
|
80
|
-
s = peer_server_socket
|
|
81
|
-
configured
|
|
82
|
-
|
|
83
|
-
Thread.new do
|
|
84
|
-
s = s.accept
|
|
85
|
-
end
|
|
86
|
-
|
|
87
|
-
IO.select( nil, [configured.socket] )
|
|
88
|
-
|
|
89
|
-
configured.peer_hostname.should == s.to_io.addr(true)[2]
|
|
90
|
-
end
|
|
91
|
-
end
|
|
92
|
-
|
|
93
|
-
describe '#peer_ip_address' do
|
|
94
|
-
let(:connection) { echo_client_handler }
|
|
95
|
-
let(:role) { :client }
|
|
96
|
-
let(:socket) { client_socket }
|
|
97
|
-
|
|
98
|
-
it 'returns the peer IP address' do
|
|
99
|
-
s = peer_server_socket
|
|
100
|
-
configured
|
|
101
|
-
|
|
102
|
-
Thread.new do
|
|
103
|
-
s = s.accept
|
|
19
|
+
connection.configure(
|
|
20
|
+
host: host,
|
|
21
|
+
port: port,
|
|
22
|
+
socket: socket,
|
|
23
|
+
role: role,
|
|
24
|
+
server_handler: server_handler
|
|
25
|
+
)
|
|
26
|
+
|
|
27
|
+
if role == :client
|
|
28
|
+
while !connection.connected?
|
|
29
|
+
begin
|
|
30
|
+
IO.select( [connection.socket], [connection.socket], nil, 0.1 )
|
|
31
|
+
rescue => e
|
|
32
|
+
ap e
|
|
33
|
+
break
|
|
104
34
|
end
|
|
105
35
|
|
|
106
|
-
|
|
107
|
-
|
|
108
|
-
configured.peer_ip_address.should == s.to_io.addr[3]
|
|
36
|
+
connection._connect
|
|
109
37
|
end
|
|
110
38
|
end
|
|
111
39
|
|
|
112
|
-
|
|
113
|
-
let(:connection) { echo_client_handler }
|
|
114
|
-
let(:role) { :client }
|
|
115
|
-
let(:socket) { client_socket }
|
|
116
|
-
|
|
117
|
-
it 'returns the peer IP address' do
|
|
118
|
-
s = peer_server_socket
|
|
119
|
-
configured
|
|
120
|
-
|
|
121
|
-
Thread.new do
|
|
122
|
-
s = s.accept
|
|
123
|
-
end
|
|
124
|
-
|
|
125
|
-
IO.select( nil, [configured.socket] )
|
|
126
|
-
|
|
127
|
-
configured.peer_port.should == s.to_io.addr[1]
|
|
128
|
-
end
|
|
129
|
-
end
|
|
40
|
+
connection
|
|
130
41
|
end
|
|
131
42
|
|
|
132
43
|
describe '#configure' do
|
|
@@ -157,12 +68,12 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
157
68
|
end
|
|
158
69
|
end
|
|
159
70
|
|
|
160
|
-
it 'calls #on_connect' do
|
|
161
|
-
|
|
162
|
-
|
|
163
|
-
|
|
164
|
-
|
|
165
|
-
end
|
|
71
|
+
# it 'calls #on_connect' do
|
|
72
|
+
# peer_server_socket
|
|
73
|
+
# connection.should receive(:on_connect)
|
|
74
|
+
# connection.reactor = reactor
|
|
75
|
+
# connection.configure socket: socket, role: role
|
|
76
|
+
# end
|
|
166
77
|
end
|
|
167
78
|
|
|
168
79
|
describe '#unix?' do
|
|
@@ -172,7 +83,7 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
172
83
|
let(:socket) { client_socket }
|
|
173
84
|
|
|
174
85
|
it 'returns false' do
|
|
175
|
-
|
|
86
|
+
peer_server_socket
|
|
176
87
|
configured
|
|
177
88
|
configured.should_not be_unix
|
|
178
89
|
end
|
|
@@ -186,7 +97,7 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
186
97
|
let(:socket) { unix_socket }
|
|
187
98
|
|
|
188
99
|
it 'returns true' do
|
|
189
|
-
|
|
100
|
+
peer_server_socket
|
|
190
101
|
configured
|
|
191
102
|
configured.should be_unix
|
|
192
103
|
end
|
|
@@ -200,7 +111,7 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
200
111
|
let(:socket) { client_socket }
|
|
201
112
|
|
|
202
113
|
it 'returns false' do
|
|
203
|
-
|
|
114
|
+
peer_server_socket
|
|
204
115
|
configured
|
|
205
116
|
configured.should be_inet
|
|
206
117
|
end
|
|
@@ -214,7 +125,7 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
214
125
|
let(:socket) { unix_socket }
|
|
215
126
|
|
|
216
127
|
it 'returns false' do
|
|
217
|
-
|
|
128
|
+
peer_server_socket
|
|
218
129
|
configured
|
|
219
130
|
configured.should_not be_inet
|
|
220
131
|
end
|
|
@@ -240,7 +151,6 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
240
151
|
if: Arachni::Reactor.supports_unix_sockets? do
|
|
241
152
|
|
|
242
153
|
let(:connection) { echo_client_handler }
|
|
243
|
-
let(:role) { :client }
|
|
244
154
|
let(:socket) { unix_server_socket }
|
|
245
155
|
|
|
246
156
|
it 'returns UNIXServer' do
|
|
@@ -278,7 +188,7 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
278
188
|
|
|
279
189
|
it 'returns TCPSocket' do
|
|
280
190
|
peer_server_socket
|
|
281
|
-
configured.to_io.should be_instance_of
|
|
191
|
+
configured.to_io.should be_instance_of Socket
|
|
282
192
|
end
|
|
283
193
|
end
|
|
284
194
|
|
|
@@ -315,7 +225,6 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
315
225
|
if: Arachni::Reactor.supports_unix_sockets? do
|
|
316
226
|
|
|
317
227
|
let(:connection) { echo_client_handler }
|
|
318
|
-
let(:role) { :client }
|
|
319
228
|
let(:socket) { unix_server_socket }
|
|
320
229
|
|
|
321
230
|
it 'returns true' do
|
|
@@ -479,7 +388,7 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
479
388
|
let(:socket) { client_socket }
|
|
480
389
|
|
|
481
390
|
it 'appends the given data to the send-buffer' do
|
|
482
|
-
|
|
391
|
+
peer_server_socket
|
|
483
392
|
reactor.run_in_thread
|
|
484
393
|
|
|
485
394
|
configured
|
|
@@ -488,8 +397,8 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
488
397
|
received = ''
|
|
489
398
|
|
|
490
399
|
t = Thread.new do
|
|
491
|
-
|
|
492
|
-
received <<
|
|
400
|
+
sleep 0.1 while !accepted
|
|
401
|
+
received << accepted.read( data.size ) while received.size != data.size
|
|
493
402
|
all_read = true
|
|
494
403
|
end
|
|
495
404
|
|
|
@@ -548,13 +457,13 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
548
457
|
let(:socket) { client_socket }
|
|
549
458
|
|
|
550
459
|
it "reads a maximum of #{Arachni::Reactor::Connection::BLOCK_SIZE} bytes at a time" do
|
|
551
|
-
|
|
460
|
+
peer_server_socket
|
|
552
461
|
configured
|
|
553
462
|
|
|
554
463
|
Thread.new do
|
|
555
|
-
|
|
556
|
-
|
|
557
|
-
|
|
464
|
+
sleep 0.1 while !accepted
|
|
465
|
+
accepted.write data
|
|
466
|
+
accepted.flush
|
|
558
467
|
end
|
|
559
468
|
|
|
560
469
|
while configured.received_data.to_s.size != data.size
|
|
@@ -567,15 +476,15 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
567
476
|
end
|
|
568
477
|
|
|
569
478
|
it 'passes the data to #on_read' do
|
|
570
|
-
|
|
479
|
+
peer_server_socket
|
|
571
480
|
configured
|
|
572
481
|
|
|
573
482
|
data = "test\n"
|
|
574
483
|
|
|
575
484
|
Thread.new do
|
|
576
|
-
|
|
577
|
-
|
|
578
|
-
|
|
485
|
+
sleep 0.1 while !accepted
|
|
486
|
+
accepted.write data
|
|
487
|
+
accepted.flush
|
|
579
488
|
end
|
|
580
489
|
|
|
581
490
|
configured._read while !configured.received_data
|
|
@@ -618,6 +527,8 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
618
527
|
reactor.run_in_thread
|
|
619
528
|
end
|
|
620
529
|
|
|
530
|
+
let(:port) { @port }
|
|
531
|
+
let(:host) { @host }
|
|
621
532
|
let(:connection) { echo_client_handler }
|
|
622
533
|
let(:role) { :client }
|
|
623
534
|
let(:socket) { echo_client }
|
|
@@ -634,7 +545,7 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
634
545
|
next
|
|
635
546
|
end
|
|
636
547
|
|
|
637
|
-
written.should
|
|
548
|
+
written.should <= block_size
|
|
638
549
|
writes += 1
|
|
639
550
|
end
|
|
640
551
|
|
|
@@ -647,17 +558,14 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
647
558
|
|
|
648
559
|
writes = 0
|
|
649
560
|
while configured.has_outgoing_data?
|
|
650
|
-
|
|
651
561
|
IO.select( nil, [configured.socket] )
|
|
652
|
-
|
|
653
|
-
|
|
654
|
-
next
|
|
655
|
-
end
|
|
562
|
+
|
|
563
|
+
next if configured._write == 0
|
|
656
564
|
|
|
657
565
|
writes += 1
|
|
658
566
|
end
|
|
659
567
|
|
|
660
|
-
configured.on_write_count.should
|
|
568
|
+
configured.on_write_count.should >= writes
|
|
661
569
|
end
|
|
662
570
|
|
|
663
571
|
context 'when the buffer is entirely consumed' do
|
|
@@ -668,12 +576,10 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
668
576
|
while configured.has_outgoing_data?
|
|
669
577
|
IO.select( nil, [configured.socket] )
|
|
670
578
|
|
|
671
|
-
if
|
|
579
|
+
if configured._write == 0
|
|
672
580
|
IO.select( [configured.socket] )
|
|
673
581
|
next
|
|
674
582
|
end
|
|
675
|
-
|
|
676
|
-
written.should == block_size
|
|
677
583
|
end
|
|
678
584
|
|
|
679
585
|
configured.called_on_flush.should be_true
|
|
@@ -682,6 +588,9 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
682
588
|
end
|
|
683
589
|
|
|
684
590
|
describe '#has_outgoing_data?' do
|
|
591
|
+
let(:port) { @port }
|
|
592
|
+
let(:host) { @host }
|
|
593
|
+
|
|
685
594
|
let(:role) { :client }
|
|
686
595
|
let(:socket) { echo_client }
|
|
687
596
|
|
|
@@ -704,6 +613,9 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
704
613
|
end
|
|
705
614
|
|
|
706
615
|
describe '#closed?' do
|
|
616
|
+
let(:port) { @port }
|
|
617
|
+
let(:host) { @host }
|
|
618
|
+
|
|
707
619
|
let(:role) { :client }
|
|
708
620
|
let(:socket) { echo_client }
|
|
709
621
|
|
|
@@ -725,6 +637,9 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
725
637
|
end
|
|
726
638
|
|
|
727
639
|
describe '#close_without_callback' do
|
|
640
|
+
let(:port) { @port }
|
|
641
|
+
let(:host) { @host }
|
|
642
|
+
|
|
728
643
|
let(:role) { :client }
|
|
729
644
|
let(:socket) { echo_client }
|
|
730
645
|
|
|
@@ -753,6 +668,9 @@ shared_examples_for 'Arachni::Reactor::Connection' do
|
|
|
753
668
|
end
|
|
754
669
|
|
|
755
670
|
describe '#close' do
|
|
671
|
+
let(:port) { @port }
|
|
672
|
+
let(:host) { @host }
|
|
673
|
+
|
|
756
674
|
let(:role) { :client }
|
|
757
675
|
let(:socket) { echo_client }
|
|
758
676
|
|
metadata
CHANGED
|
@@ -1,14 +1,14 @@
|
|
|
1
1
|
--- !ruby/object:Gem::Specification
|
|
2
2
|
name: arachni-reactor
|
|
3
3
|
version: !ruby/object:Gem::Version
|
|
4
|
-
version: 0.1.0
|
|
4
|
+
version: 0.1.0
|
|
5
5
|
platform: ruby
|
|
6
6
|
authors:
|
|
7
7
|
- Tasos Laskos
|
|
8
8
|
autorequire:
|
|
9
9
|
bindir: bin
|
|
10
10
|
cert_chain: []
|
|
11
|
-
date:
|
|
11
|
+
date: 2015-03-21 00:00:00.000000000 Z
|
|
12
12
|
dependencies: []
|
|
13
13
|
description: |2
|
|
14
14
|
Arachni::Reactor is a simple, lightweight, pure-Ruby implementation of the Reactor
|
|
@@ -93,12 +93,12 @@ required_ruby_version: !ruby/object:Gem::Requirement
|
|
|
93
93
|
version: '0'
|
|
94
94
|
required_rubygems_version: !ruby/object:Gem::Requirement
|
|
95
95
|
requirements:
|
|
96
|
-
- - "
|
|
96
|
+
- - ">="
|
|
97
97
|
- !ruby/object:Gem::Version
|
|
98
|
-
version:
|
|
98
|
+
version: '0'
|
|
99
99
|
requirements: []
|
|
100
100
|
rubyforge_project:
|
|
101
|
-
rubygems_version: 2.
|
|
101
|
+
rubygems_version: 2.4.5
|
|
102
102
|
signing_key:
|
|
103
103
|
specification_version: 4
|
|
104
104
|
summary: A pure-Ruby implementation of the Reactor pattern.
|