arachni-reactor 0.1.0.beta5 → 0.1.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: f7671f97abb22c56a6488378023cd84ad92a8f30
4
- data.tar.gz: ffd8c0513e0c41d4483249faaeeea3d9eea5aa21
3
+ metadata.gz: d8f90922fd68d3df405cf0aa7537924db3f3c118
4
+ data.tar.gz: 5bd9e5042618276a83909b43879651d60f8e0538
5
5
  SHA512:
6
- metadata.gz: 5678c3dd7c6e90aa2061f06c892a4889538baee925550db1f5a46fc3ff232a5c66849ae1fef8c24fe6ae06d1e066dc8bfc2570b6f996dfe89ce33effd6d8e86c
7
- data.tar.gz: 8c5ebfd3235211408111216a1dbf942266354f085e14cd629ae56eda7ddb91126b9b4ccbf3705aa2732cf28a45d45598a2aaeea7eabad9af08c1486abd5b26f5
6
+ metadata.gz: ff7c11326a30b31030b95ac93cd7ee3e5c37ab6f7097bb6f9a4829354b13bc683d484e8243bb9d14e88b8248bd69481a9a43ac01d475a708e61199595ec4632b
7
+ data.tar.gz: f1563d0bafe856937029267327fa8c049b05a56122e8fa8dd5c1fd0b45bb7e9784f250eb8dfd4d6438d8b866cd402de4340b9382d5a304c204fd54552c4a389c
@@ -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.beta5</td>
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 (Without OpenSSL support)
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 --pre
66
+ gem install arachni-reactor
67
67
 
68
68
  ## Running the Specs
69
69
 
@@ -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.socket] = 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.socket
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.socket
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( host, port )
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
- grouped_sockets =
646
+ readables = read_sockets
647
+
648
+ selected_sockets =
654
649
  begin
655
650
  Connection::Error.translate do
656
651
  select(
657
- read_sockets,
652
+ readables,
658
653
  write_sockets,
659
- read_sockets, # Read sockets are actually all sockets.
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
- return {} if !grouped_sockets
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: connections_from_sockets( grouped_sockets[1] ),
672
- read: connections_from_sockets( grouped_sockets[0] ),
673
- error: connections_from_sockets( grouped_sockets[2] )
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.keys
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 |socket, connection|
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 buffer, **all** of it, or at least try to.
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
- begin
66
- @socket.connect_nonblock
67
- rescue IO::WaitReadable, IO::WaitWritable
68
- end
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
- socket = nil
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
- begin
98
- socket.accept_nonblock
99
- rescue IO::WaitReadable, IO::WaitWritable
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
- socket
103
- rescue OpenSSL::SSL::SSLError
155
+ rescue IO::WaitReadable, IO::WaitWritable
156
+ rescue Error => e
157
+ close e
104
158
  end
105
159
 
106
160
  end
@@ -9,7 +9,7 @@
9
9
  module Arachni
10
10
  class Reactor
11
11
 
12
- VERSION = '0.1.0.beta5'
12
+ VERSION = '0.1.0'
13
13
 
14
14
  end
15
15
  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) { tcp_connect( @host, @port ) }
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) { tcp_ssl_server( host, port ) }
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) { tcp_connect( host, port ) }
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
- s = server.accept
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
- s = server.accept
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) { tcp_connect( @host, @port ) }
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) { tcp_server( host, port ) }
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) { tcp_connect( host, port ) }
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
@@ -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
- 'ruby', RUNNER, server_info[:path], '-p', server_info[:port].to_s,
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 !(line = socket.gets)
8
- socket.write( line )
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
@@ -12,8 +12,8 @@ loop do
12
12
  Thread.new do
13
13
  begin
14
14
  loop do
15
- next if (line = socket.gets).to_s.empty?
16
- socket.write( line )
15
+ next if (data = socket.gets).to_s.empty?
16
+ socket.write( data )
17
17
  end
18
18
  rescue EOFError, Errno::EPIPE
19
19
  socket.close
@@ -4,8 +4,8 @@ loop do
4
4
  Thread.new server.accept do |socket|
5
5
  begin
6
6
  loop do
7
- next if !(line = socket.gets)
8
- socket.write( line )
7
+ next if (data = socket.gets).to_s.empty?
8
+ socket.write( data )
9
9
  end
10
10
  rescue EOFError, Errno::EPIPE
11
11
  socket.close
@@ -12,8 +12,8 @@ loop do
12
12
  Thread.new do
13
13
  begin
14
14
  loop do
15
- next if (line = socket.gets).to_s.empty?
16
- socket.write( line )
15
+ next if (data = socket.gets).to_s.empty?
16
+ socket.write( data )
17
17
  end
18
18
  rescue EOFError, Errno::EPIPE
19
19
  socket.close
@@ -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 socket, role, server_handler
20
- connection
21
- end
22
-
23
- # This needs to be put in a file of its own.
24
- describe '::PeerInfo' do
25
- describe '#peer_address_info' do
26
- context 'when using an IP socket' do
27
- let(:connection) { echo_client_handler }
28
- let(:role) { :client }
29
- let(:socket) { client_socket }
30
-
31
- it 'returns IP address information' do
32
- s = peer_server_socket
33
- configured
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
- IO.select( nil, [configured.socket] )
107
-
108
- configured.peer_ip_address.should == s.to_io.addr[3]
36
+ connection._connect
109
37
  end
110
38
  end
111
39
 
112
- describe '#peer_port' do
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
- peer_server_socket
162
- connection.should receive(:on_connect)
163
- connection.reactor = reactor
164
- connection.configure socket, role
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
- s = peer_server_socket
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
- s = peer_server_socket
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
- s = peer_server_socket
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
- s = peer_server_socket
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 TCPSocket
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
- s = peer_server_socket
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
- s = s.accept
492
- received << s.read( data.size ) while received.size != data.size
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
- s = peer_server_socket
460
+ peer_server_socket
552
461
  configured
553
462
 
554
463
  Thread.new do
555
- s = s.accept
556
- s.write data
557
- s.flush
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
- s = peer_server_socket
479
+ peer_server_socket
571
480
  configured
572
481
 
573
482
  data = "test\n"
574
483
 
575
484
  Thread.new do
576
- s = s.accept
577
- s.write data
578
- s.flush
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 == block_size
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
- if configured._write == 0
653
- IO.select( [configured.socket] )
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 == writes
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 (written = configured._write) == 0
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.beta5
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: 2014-09-04 00:00:00.000000000 Z
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: 1.3.1
98
+ version: '0'
99
99
  requirements: []
100
100
  rubyforge_project:
101
- rubygems_version: 2.2.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.