arachni-rpc-em 0.1.1 → 0.1.2

Sign up to get free protection for your applications and to get access to all the features.
data/CHANGELOG.md CHANGED
@@ -0,0 +1,6 @@
1
+ # ChangeLog
2
+
3
+ ## Version 0.1.2 _(Under development)_
4
+
5
+ - Code cleanup
6
+ - Client retries on Errno::ECONNREFUSED
data/README.md CHANGED
@@ -2,7 +2,7 @@
2
2
  <table>
3
3
  <tr>
4
4
  <th>Version</th>
5
- <td>0.1.1</td>
5
+ <td>0.1.2</td>
6
6
  </tr>
7
7
  <tr>
8
8
  <th>Github page</th>
@@ -14,7 +14,7 @@
14
14
  </tr>
15
15
  <tr>
16
16
  <th>Author</th>
17
- <td><a href="mailto:tasos.laskos@gmail.com">Tasos</a> "<a href="mailto:zapotek@segfault.gr">Zapotek</a>" <a href="mailto:tasos.laskos@gmail.com">Laskos</a></td>
17
+ <td><a href="mailto:tasos.laskos@gmail.com">Tasos "Zapotek" Laskos</a></td>
18
18
  </tr>
19
19
  <tr>
20
20
  <th>Twitter</th>
@@ -22,7 +22,7 @@
22
22
  </tr>
23
23
  <tr>
24
24
  <th>Copyright</th>
25
- <td>2011</td>
25
+ <td>2011-2012</td>
26
26
  </tr>
27
27
  <tr>
28
28
  <th>License</th>
@@ -33,7 +33,6 @@
33
33
  ## Synopsis
34
34
 
35
35
  Arachni-RPC EM is an implementation of the <a href="http://github.com/Arachni/arachni-rpc">Arachni-RPC</a> protocol using EventMachine and provides both a server and a client. <br/>
36
- It is under development and will ultimately form the basis for <a href="http://arachni.segfault.gr">Arachni</a>'s Grid infrastructure.
37
36
 
38
37
  ## Features
39
38
 
@@ -66,13 +65,6 @@ If you want to clone the repository and work with the source code:
66
65
 
67
66
  ## Running the Specs
68
67
 
69
- In order to run the specs you must first fire up 2 sample servers like so:
70
-
71
- ruby spec/servers/basic.rb
72
- ruby spec/servers/with_ssl_primitives.rb
73
-
74
- Then:
75
-
76
68
  rake spec
77
69
 
78
70
  ## Bug reports/Feature requests
data/Rakefile CHANGED
@@ -7,17 +7,21 @@
7
7
  =end
8
8
 
9
9
  require 'rubygems'
10
- require 'rspec'
11
- require 'rspec/core/rake_task'
12
-
13
10
  require File.expand_path( File.dirname( __FILE__ ) ) + '/lib/arachni/rpc/em/version'
14
11
 
15
- RSpec::Core::RakeTask.new do |t|
16
- t.rspec_opts = ['--options', "\"#{File.dirname(__FILE__)}/spec/spec.opts\""]
12
+ begin
13
+ require 'rspec'
14
+ require 'rspec/core/rake_task'
15
+
16
+ RSpec::Core::RakeTask.new
17
+ rescue LoadError => e
18
+ puts 'If you want to run the tests please install rspec first:'
19
+ puts ' gem install rspec'
17
20
  end
18
21
 
19
- desc "Generate docs"
22
+ task default: [ :spec ]
20
23
 
24
+ desc "Generate docs"
21
25
  task :docs do
22
26
 
23
27
  outdir = "../arachni-rpc-pages"
@@ -32,39 +36,22 @@ task :docs do
32
36
  sh "rm -rf .yard*"
33
37
  end
34
38
 
35
-
36
- #
37
- # Cleans reports and logs
38
- #
39
39
  desc "Cleaning..."
40
40
  task :clean do
41
41
  sh "rm *.gem || true"
42
42
  end
43
43
 
44
-
45
-
46
- #
47
- # Building
48
- #
49
44
  desc "Build the arachni-rpc-em gem."
50
45
  task :build => [ :clean ] do
51
46
  sh "gem build arachni-rpc-em.gemspec"
52
47
  end
53
48
 
54
-
55
- #
56
- # Installing
57
- #
58
49
  desc "Build and install the arachni gem."
59
50
  task :install => [ :build ] do
60
51
 
61
52
  sh "gem install arachni-rpc-em-#{Arachni::RPC::EM::VERSION}.gem"
62
53
  end
63
54
 
64
-
65
- #
66
- # Publishing
67
- #
68
55
  desc "Push a new version to Gemcutter"
69
56
  task :publish => [ :build ] do
70
57
 
@@ -16,9 +16,10 @@ require 'arachni/rpc'
16
16
  require 'yaml'
17
17
  YAML::ENGINE.yamler = 'syck'
18
18
 
19
- require File.join( File.expand_path( File.dirname( __FILE__ ) ), 'em', 'connection_utilities' )
20
- require File.join( File.expand_path( File.dirname( __FILE__ ) ), 'em', 'ssl' )
21
- require File.join( File.expand_path( File.dirname( __FILE__ ) ), 'em', 'protocol' )
22
- require File.join( File.expand_path( File.dirname( __FILE__ ) ), 'em', 'server' )
23
- require File.join( File.expand_path( File.dirname( __FILE__ ) ), 'em', 'client' )
24
- require File.join( File.expand_path( File.dirname( __FILE__ ) ), 'em', 'em' )
19
+ dir = File.expand_path( File.dirname( __FILE__ ) )
20
+ require File.join( dir, 'em', 'connection_utilities' )
21
+ require File.join( dir, 'em', 'ssl' )
22
+ require File.join( dir, 'em', 'protocol' )
23
+ require File.join( dir, 'em', 'server' )
24
+ require File.join( dir, 'em', 'client' )
25
+ require File.join( dir, 'em', 'em' )
@@ -19,13 +19,9 @@ module EM
19
19
  # - asynchronous and synchronous requests
20
20
  # - handling remote asynchronous calls that require a block
21
21
  #
22
- # @author: Tasos "Zapotek" Laskos
23
- # <tasos.laskos@gmail.com>
24
- # <zapotek@segfault.gr>
25
- # @version: 0.1
22
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
26
23
  #
27
24
  class Client
28
-
29
25
  include ::Arachni::RPC::Exceptions
30
26
 
31
27
  #
@@ -34,17 +30,20 @@ class Client
34
30
  # It's responsible for TLS, storing and calling callbacks as well as
35
31
  # serializing, transmitting and receiving objects.
36
32
  #
37
- # @author: Tasos "Zapotek" Laskos
38
- # <tasos.laskos@gmail.com>
39
- # <zapotek@segfault.gr>
40
- # @version: 0.1
33
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
41
34
  #
42
35
  class Handler < EventMachine::Connection
43
36
  include ::Arachni::RPC::EM::Protocol
44
37
  include ::Arachni::RPC::EM::ConnectionUtilities
45
38
 
39
+ DEFAULT_TRIES = 9
40
+
46
41
  def initialize( opts )
47
42
  @opts = opts
43
+ @max_retries = @opts[:max_retries] || DEFAULT_TRIES
44
+ @opts[:tries] ||= 0
45
+ @tries = @opts[:tries]
46
+
48
47
  @status = :idle
49
48
 
50
49
  @request = nil
@@ -59,11 +58,14 @@ class Client
59
58
  def unbind( reason )
60
59
  end_ssl
61
60
 
62
- if @request && @request.callback && @status != :done
63
- e = Arachni::RPC::Exceptions::ConnectionError.new( "Connection closed [#{reason}]" )
64
- @request.callback.call( e )
61
+ if @request && @request.callback && status != :done
62
+ if reason == Errno::ECONNREFUSED && retry?
63
+ retry_request
64
+ else
65
+ e = Arachni::RPC::Exceptions::ConnectionError.new( "Connection closed [#{reason}]" )
66
+ @request.callback.call( e )
67
+ end
65
68
  end
66
-
67
69
  @status = :closed
68
70
  end
69
71
 
@@ -81,32 +83,43 @@ class Client
81
83
  # @param [Arachni::RPC::EM::Response] res
82
84
  #
83
85
  def receive_response( res )
86
+ @status = :done
84
87
 
85
88
  if exception?( res )
86
89
  res.obj = Arachni::RPC::Exceptions.from_response( res )
87
90
  end
88
91
 
92
+
89
93
  if cb = @request.callback
90
94
 
91
- callback = Proc.new {
92
- |obj|
95
+ callback = Proc.new do |obj|
93
96
  cb.call( obj )
94
-
95
- @status = :done
96
97
  close_connection
97
- }
98
+ end
98
99
 
99
100
  if @request.defer?
100
101
  # the callback might block a bit so tell EM to put it in a thread
101
- ::EM.defer {
102
- callback.call( res.obj )
103
- }
102
+ ::EM.defer { callback.call( res.obj ) }
104
103
  else
105
104
  callback.call( res.obj )
106
105
  end
107
106
  end
108
107
  end
109
108
 
109
+ def retry_request
110
+ opts = @opts.dup
111
+ opts[:tries] += 1
112
+ EventMachine::Timer.new( 0.1 ){
113
+ sleep( 0.1 )
114
+ close_connection
115
+ ::EM.connect( opts[:host], opts[:port], self.class, opts ).send_request( @request )
116
+ }
117
+ end
118
+
119
+ def retry?
120
+ @tries < @max_retries
121
+ end
122
+
110
123
  # @param [Arachni::RPC::EM::Response] res
111
124
  def exception?( res )
112
125
  res.obj.is_a?( Hash ) && res.obj['exception'] ? true : false
@@ -149,6 +162,8 @@ class Client
149
162
  # # http://eventmachine.rubyforge.org/EventMachine/Protocols/ObjectProtocol.html#M000369
150
163
  # :serializer => Marshal,
151
164
  #
165
+ # :max_retries => 0,
166
+ #
152
167
  # #
153
168
  # # In order to enable peer verification one must first provide
154
169
  # # the following:
@@ -164,14 +179,13 @@ class Client
164
179
  # @param [Hash] opts
165
180
  #
166
181
  def initialize( opts )
167
-
168
182
  begin
169
- @opts = opts.merge( :role => :client )
183
+ @opts = opts.merge( role: :client )
170
184
  @token = @opts[:token]
171
185
 
172
186
  @host, @port = @opts[:host], @opts[:port]
173
187
 
174
- Arachni::RPC::EM.ensure_em_running!
188
+ Arachni::RPC::EM.ensure_em_running
175
189
  rescue EventMachine::ConnectionError => e
176
190
  exc = ConnectionError.new( e.to_s + " for '#{@k}'." )
177
191
  exc.set_backtrace( e.backtrace )
@@ -199,22 +213,21 @@ class Client
199
213
  # res = server.call( 'handler.method', arg1, arg2 )
200
214
  #
201
215
  # @param [String] msg in the form of <i>handler.method</i>
202
- # @param [Array] args collection of argumenta to be passed to the method
216
+ # @param [Array] args collection of arguments to be passed to the method
203
217
  # @param [Proc] &block
204
218
  #
205
219
  def call( msg, *args, &block )
206
-
207
220
  req = Request.new(
208
- :message => msg,
209
- :args => args,
210
- :callback => block,
211
- :token => @token
221
+ message: msg,
222
+ args: args,
223
+ callback: block,
224
+ token: @token
212
225
  )
213
226
 
214
227
  if block_given?
215
228
  call_async( req )
216
229
  else
217
- return call_sync( req )
230
+ call_sync( req )
218
231
  end
219
232
  end
220
233
 
@@ -232,28 +245,24 @@ class Client
232
245
  end
233
246
 
234
247
  def call_sync( req )
235
-
236
248
  ret = nil
249
+
237
250
  # if we're in the Reactor thread use a Fiber and if we're not
238
251
  # use a Thread
239
252
  if !::EM::reactor_thread?
240
253
  t = Thread.current
241
- call_async( req ) {
242
- |obj|
254
+ call_async( req ) do |obj|
243
255
  t.wakeup
244
256
  ret = obj
245
- }
257
+ end
246
258
  sleep
247
259
  else
248
260
  # Fibers do not work across threads so don't defer the callback
249
261
  # once the Handler gets to it
250
- req.do_not_defer!
262
+ req.do_not_defer
251
263
 
252
264
  f = Fiber.current
253
- call_async( req ) {
254
- |obj|
255
- f.resume( obj )
256
- }
265
+ call_async( req ) { |obj| f.resume( obj ) }
257
266
 
258
267
  begin
259
268
  ret = Fiber.yield
@@ -268,7 +277,7 @@ class Client
268
277
  end
269
278
 
270
279
  raise ret if ret.is_a?( Exception )
271
- return ret
280
+ ret
272
281
  end
273
282
 
274
283
  end
@@ -13,10 +13,7 @@ module EM
13
13
  #
14
14
  # Helper methods to be included in EventMachine::Connection classes
15
15
  #
16
- # @author: Tasos "Zapotek" Laskos
17
- # <tasos.laskos@gmail.com>
18
- # <zapotek@segfault.gr>
19
- # @version: 0.1
16
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
20
17
  #
21
18
  module ConnectionUtilities
22
19
 
@@ -12,59 +12,32 @@ module RPC
12
12
  #
13
13
  # Provides some convenient methods for EventMachine's Reactor.
14
14
  #
15
- # @author: Tasos "Zapotek" Laskos
16
- # <tasos.laskos@gmail.com>
17
- # <zapotek@segfault.gr>
18
- # @version: 0.1
15
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
19
16
  #
20
17
  module EM
21
18
 
22
- module Synchrony
23
-
24
- def run( &block )
25
- @@root_f = Fiber.new {
26
- block.call
27
- }.resume
28
- end
29
-
30
- extend self
31
-
32
- end
19
+ module Synchrony
20
+ def run( &block )
21
+ Fiber.new{ block.call }.resume
22
+ end
33
23
 
34
- #
35
- # Inits method variables for the Reactor tasks and its Mutex.
36
- #
37
- def init
38
- @@reactor_tasks_mutex ||= Mutex.new
39
- @@reactor_tasks ||= []
24
+ extend self
40
25
  end
41
26
 
42
27
  #
43
- # Adds a block in the Reactor.
28
+ # Schedules a block to be run in the EM reactor.
44
29
  #
45
- # @param [Proc] &block block to be included in the Reactor loop
30
+ # @param [Proc] &block
46
31
  #
47
- def add_to_reactor( &block )
48
-
49
- self.init
50
-
51
- # if we're already in the Reactor thread just run the block straight up.
52
- if ::EM::reactor_thread?
53
- block.call
54
- else
55
- @@reactor_tasks_mutex.lock
56
- @@reactor_tasks << block
57
-
58
- ensure_em_running!
59
- @@reactor_tasks_mutex.unlock
60
- end
61
-
32
+ def schedule( &block )
33
+ ensure_em_running
34
+ ::EM.schedule( &block )
62
35
  end
63
36
 
64
37
  #
65
38
  # Blocks until the Reactor stops running
66
39
  #
67
- def block!
40
+ def block
68
41
  # beware of deadlocks, we can't join our own thread
69
42
  ::EM.reactor_thread.join if ::EM.reactor_thread && !::EM::reactor_thread?
70
43
  end
@@ -72,28 +45,20 @@ end
72
45
  #
73
46
  # Puts the Reactor in its own thread and runs it.
74
47
  #
75
- # It also runs all blocks sent to {#add_to_reactor}.
76
- #
77
- def ensure_em_running!
78
- self.init
79
-
48
+ def ensure_em_running
80
49
  if !::EM::reactor_running?
81
- q = Queue.new
82
50
 
83
51
  Thread.new do
84
52
  ::EM::run do
85
-
86
53
  ::EM.error_handler do |e|
87
54
  $stderr.puts "Exception raised during event loop: " +
88
55
  "#{e.message} (#{e.class})\n#{(e.backtrace ||
89
56
  [])[0..5].join("\n")}"
90
57
  end
91
-
92
- @@reactor_tasks.each { |task| task.call }
93
- q << true
94
58
  end
95
59
  end
96
- q.pop
60
+
61
+ sleep 0.1 while !::EM.reactor_running?
97
62
  end
98
63
  end
99
64
 
@@ -13,10 +13,7 @@ module EM
13
13
  #
14
14
  # Provides helper transport methods for {Message} transmission.
15
15
  #
16
- # @author: Tasos "Zapotek" Laskos
17
- # <tasos.laskos@gmail.com>
18
- # <zapotek@segfault.gr>
19
- # @version: 0.1
16
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
20
17
  #
21
18
  module Protocol
22
19
  include ::Arachni::RPC::EM::SSL
@@ -73,9 +70,7 @@ module Protocol
73
70
  # @param [Arachni::RPC::EM::Message] msg
74
71
  #
75
72
  def send_message( msg )
76
- ::EM.schedule {
77
- send_object( msg.prepare_for_tx )
78
- }
73
+ ::EM.schedule { send_object( msg.prepare_for_tx ) }
79
74
  end
80
75
  alias :send_request :send_message
81
76
  alias :send_response :send_message
@@ -128,7 +123,7 @@ module Protocol
128
123
  data = serializer.dump( obj )
129
124
  packed = [data.bytesize, data].pack( 'Na*' )
130
125
 
131
- while( packed )
126
+ while packed
132
127
  if packed.bytesize > MAX_CHUNK_SIZE
133
128
  send_data( packed.slice!( 0, MAX_CHUNK_SIZE ) )
134
129
  else
@@ -19,13 +19,9 @@ module EM
19
19
  # - asynchronous and synchronous requests
20
20
  # - handling asynchronous methods that require a block
21
21
  #
22
- # @author: Tasos "Zapotek" Laskos
23
- # <tasos.laskos@gmail.com>
24
- # <zapotek@segfault.gr>
25
- # @version: 0.1
22
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
26
23
  #
27
24
  class Server
28
-
29
25
  include ::Arachni::RPC::Exceptions
30
26
 
31
27
  #
@@ -36,13 +32,9 @@ class Server
36
32
  #
37
33
  # It also handles and forwards exceptions.
38
34
  #
39
- # @author: Tasos "Zapotek" Laskos
40
- # <tasos.laskos@gmail.com>
41
- # <zapotek@segfault.gr>
42
- # @version: 0.1
35
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
43
36
  #
44
37
  class Proxy < EventMachine::Connection
45
-
46
38
  include ::Arachni::RPC::EM::Protocol
47
39
  include ::Arachni::RPC::Exceptions
48
40
  include ::Arachni::RPC::EM::ConnectionUtilities
@@ -156,7 +148,7 @@ class Server
156
148
  msg + " [on behalf of #{peer_ip_addr}]"
157
149
  }
158
150
 
159
- raise( InvalidToken.new( msg ) )
151
+ raise InvalidToken.new( msg )
160
152
  end
161
153
  end
162
154
 
@@ -269,11 +261,10 @@ class Server
269
261
  @methods[name] = Set.new # no lookup overhead please :)
270
262
  @async_methods[name] = Set.new
271
263
 
272
- obj.class.public_instance_methods( false ).each {
273
- |method|
264
+ obj.class.public_instance_methods( false ).each do |method|
274
265
  @methods[name] << method.to_s
275
266
  @async_methods[name] << method.to_s if async_check( obj.method( method ) )
276
- }
267
+ end
277
268
  end
278
269
 
279
270
  #
@@ -292,10 +283,8 @@ class Server
292
283
  # Runs the server and blocks.
293
284
  #
294
285
  def run
295
- Arachni::RPC::EM.add_to_reactor {
296
- start
297
- }
298
- Arachni::RPC::EM.block!
286
+ Arachni::RPC::EM.schedule { start }
287
+ Arachni::RPC::EM.block
299
288
  end
300
289
 
301
290
  #
@@ -338,21 +327,20 @@ class Server
338
327
  if !res.async?
339
328
  res.obj = @objects[obj_name].send( meth_name.to_sym, *args )
340
329
  else
341
- @objects[obj_name].send( meth_name.to_sym, *args ){
342
- |obj|
330
+ @objects[obj_name].send( meth_name.to_sym, *args ) do |obj|
343
331
  res.obj = obj
344
332
  connection.send_response( res )
345
- }
333
+ end
346
334
  end
347
335
 
348
- return res
336
+ res
349
337
  end
350
338
 
351
339
  #
352
340
  # @return [TrueClass]
353
341
  #
354
342
  def alive?
355
- return true
343
+ true
356
344
  end
357
345
 
358
346
  #
@@ -365,7 +353,7 @@ class Server
365
353
 
366
354
  # don't die before returning
367
355
  EventMachine::add_timer( wait_for ) { ::EM.stop }
368
- return true
356
+ true
369
357
  end
370
358
 
371
359
  private
@@ -375,11 +363,8 @@ class Server
375
363
  end
376
364
 
377
365
  def async_check( method )
378
- @async_checks.each {
379
- |check|
380
- return true if check.call( method )
381
- }
382
- return false
366
+ @async_checks.each { |check| return true if check.call( method ) }
367
+ false
383
368
  end
384
369
 
385
370
 
@@ -399,7 +384,6 @@ class Server
399
384
 
400
385
  def parse_expr( expr )
401
386
  parts = expr.to_s.split( '.' )
402
-
403
387
  # method name, object name
404
388
  [ parts.pop, parts.join( '.' ) ]
405
389
  end
@@ -40,13 +40,9 @@ module EM
40
40
  #
41
41
  # @see https://gist.github.com/1151454
42
42
  #
43
- # @author: Tasos "Zapotek" Laskos
44
- # <tasos.laskos@gmail.com>
45
- # <zapotek@segfault.gr>
46
- # @version: 0.1
43
+ # @author: Tasos "Zapotek" Laskos <tasos.laskos@gmail.com>
47
44
  #
48
45
  module SSL
49
-
50
46
  include ::Arachni::RPC::EM::ConnectionUtilities
51
47
 
52
48
  #
@@ -58,13 +54,11 @@ module SSL
58
54
 
59
55
  ssl_opts = {}
60
56
  if ssl_opts?
61
-
62
57
  ssl_opts = {
63
- :private_key_file => @opts[:ssl_pkey],
64
- :cert_chain_file => @opts[:ssl_cert],
65
- :verify_peer => true
66
- }
67
-
58
+ private_key_file: @opts[:ssl_pkey],
59
+ cert_chain_file: @opts[:ssl_cert],
60
+ verify_peer: true
61
+ }
68
62
  @last_seen_cert = nil
69
63
  end
70
64
 
@@ -110,7 +104,7 @@ module SSL
110
104
  end
111
105
  end
112
106
 
113
- return @ca_store
107
+ @ca_store
114
108
  end
115
109
 
116
110
  #
@@ -119,7 +113,6 @@ module SSL
119
113
  # @see http://eventmachine.rubyforge.org/EventMachine/Connection.html#M000271
120
114
  #
121
115
  def ssl_verify_peer( cert_string )
122
-
123
116
  cert = OpenSSL::X509::Certificate.new( cert_string )
124
117
 
125
118
  # Some servers send the same certificate multiple times. I'm not even
@@ -134,12 +127,12 @@ module SSL
134
127
  ca_store.add_cert( @last_seen_cert ) if !@last_seen_cert.root?
135
128
 
136
129
  @verified_peer = true
137
- return true
130
+ true
138
131
  else
139
132
  log( :error, 'SSL',
140
133
  "#{ca_store.error_string.capitalize} ['#{peer_ip_addr}']."
141
134
  )
142
- return false
135
+ false
143
136
  end
144
137
  end
145
138
 
@@ -9,7 +9,7 @@
9
9
  module Arachni
10
10
  module RPC
11
11
  module EM
12
- VERSION = '0.1.1'
12
+ VERSION = '0.1.2'
13
13
  end
14
14
  end
15
15
  end
@@ -3,11 +3,8 @@ require File.join( File.expand_path( File.dirname( __FILE__ ) ), '../../../', 's
3
3
  describe Arachni::RPC::EM::Client do
4
4
 
5
5
  before( :all ) do
6
- @arg = [
7
- 'one',
8
- 2,
9
- { :three => 3 },
10
- [ 4 ]
6
+ @arg = [ 'one', 2,
7
+ { :three => 3 }, [ 4 ]
11
8
  ]
12
9
  end
13
10
 
@@ -27,37 +24,32 @@ describe Arachni::RPC::EM::Client do
27
24
  end
28
25
 
29
26
  it "should be able to perform asynchronous calls" do
30
- start_client( rpc_opts ).call( 'test.foo', @arg ) {
31
- |res|
27
+ start_client( rpc_opts ).call( 'test.foo', @arg ) do |res|
32
28
  @arg.should == res
33
29
  ::EM.stop
34
- }
35
- Arachni::RPC::EM.block!
30
+ end
31
+ Arachni::RPC::EM.block
36
32
  end
37
33
  end
38
34
 
39
35
  context "when run inside the Reactor loop" do
40
36
 
41
37
  it "should be able to perform synchronous calls" do
42
- ::EM.run do
43
-
38
+ ::EM.run {
44
39
  ::Arachni::RPC::EM::Synchrony.run do
45
40
  @arg.should == start_client( rpc_opts ).call( 'test.foo', @arg )
46
41
  ::EM.stop
47
42
  end
48
- end
43
+ }
49
44
  end
50
45
 
51
46
  it "should be able to perform asynchronous calls" do
52
- ::EM.run do
53
-
54
- start_client( rpc_opts ).call( 'test.foo', @arg ) {
55
- |res|
47
+ ::EM.run {
48
+ start_client( rpc_opts ).call( 'test.foo', @arg ) do |res|
56
49
  res.should == @arg
57
50
  ::EM.stop
58
- }
59
-
60
- end
51
+ end
52
+ }
61
53
  end
62
54
 
63
55
  end
@@ -72,12 +64,11 @@ describe Arachni::RPC::EM::Client do
72
64
 
73
65
  it "should be able to properly forward synchronous calls" do
74
66
  test = Arachni::RPC::RemoteObjectMapper.new( start_client( rpc_opts ), 'test' )
75
- test.foo( @arg ) {
76
- |res|
67
+ test.foo( @arg ) do |res|
77
68
  res.should == @arg
78
69
  ::EM.stop
79
- }
80
- Arachni::RPC::EM.block!
70
+ end
71
+ Arachni::RPC::EM.block
81
72
  end
82
73
  end
83
74
 
@@ -85,30 +76,27 @@ describe Arachni::RPC::EM::Client do
85
76
  context 'when performing asynchronous calls' do
86
77
 
87
78
  it "should be returned when requesting inexistent objects" do
88
- start_client( rpc_opts ).call( 'bar.foo' ) {
89
- |res|
79
+ start_client( rpc_opts ).call( 'bar.foo' ) do |res|
90
80
  res.rpc_invalid_object_error?.should be_true
91
81
  ::EM.stop
92
- }
93
- Arachni::RPC::EM.block!
82
+ end
83
+ Arachni::RPC::EM.block
94
84
  end
95
85
 
96
86
  it "should be returned when requesting inexistent or non-public methods" do
97
- start_client( rpc_opts ).call( 'test.bar' ) {
98
- |res|
87
+ start_client( rpc_opts ).call( 'test.bar' ) do |res|
99
88
  res.rpc_invalid_method_error?.should be_true
100
89
  ::EM.stop
101
- }
102
- Arachni::RPC::EM.block!
90
+ end
91
+ Arachni::RPC::EM.block
103
92
  end
104
93
 
105
94
  it "should be returned when there's a remote exception" do
106
- start_client( rpc_opts ).call( 'test.foo' ) {
107
- |res|
95
+ start_client( rpc_opts ).call( 'test.foo' ) do |res|
108
96
  res.rpc_remote_exception?.should be_true
109
97
  ::EM.stop
110
- }
111
- Arachni::RPC::EM.block!
98
+ end
99
+ Arachni::RPC::EM.block
112
100
  end
113
101
 
114
102
  end
@@ -146,35 +134,30 @@ describe Arachni::RPC::EM::Client do
146
134
  it "should be able to retain stability and consistency under heavy load" do
147
135
  client = start_client( rpc_opts )
148
136
 
149
- n = 1000
137
+ n = 400
150
138
  cnt = 0
151
139
 
152
140
  mismatches = []
153
141
 
154
- n.times {
155
- |i|
156
- client.call( 'test.foo', i ) {
157
- |res|
158
-
142
+ n.times do |i|
143
+ client.call( 'test.foo', i ) do |res|
159
144
  cnt += 1
160
-
161
145
  mismatches << [i, res] if i != res
162
146
  ::EM.stop if cnt == n || !mismatches.empty?
163
- }
164
- }
165
-
166
- Arachni::RPC::EM.block!
147
+ end
148
+ end
167
149
 
150
+ Arachni::RPC::EM.block
151
+ cnt.should > 0
168
152
  mismatches.should be_empty
169
153
  end
170
154
 
171
155
  it "should throw error when connecting to inexistent server" do
172
- start_client( rpc_opts.merge( :port => 9999 ) ).call( 'test.foo', @arg ) {
173
- |res|
156
+ start_client( rpc_opts.merge( :port => 9999 ) ).call( 'test.foo', @arg ) do |res|
174
157
  res.rpc_connection_error?.should be_true
175
158
  ::EM.stop
176
- }
177
- Arachni::RPC::EM.block!
159
+ end
160
+ Arachni::RPC::EM.block
178
161
  end
179
162
 
180
163
  context "when using valid SSL primitives" do
@@ -187,24 +170,22 @@ describe Arachni::RPC::EM::Client do
187
170
 
188
171
  context "when using invalid SSL primitives" do
189
172
  it "should not be able to establish a connection" do
190
- start_client( rpc_opts_with_invalid_ssl_primitives ).call( 'test.foo', @arg ){
191
- |res|
173
+ start_client( rpc_opts_with_invalid_ssl_primitives ).call( 'test.foo', @arg ) do |res|
192
174
  res.rpc_connection_error?.should be_true
193
175
  ::EM.stop
194
- }
195
- Arachni::RPC::EM.block!
176
+ end
177
+ Arachni::RPC::EM.block
196
178
  end
197
179
  end
198
180
 
199
181
  context "when using mixed SSL primitives" do
200
182
  it "should not be able to establish a connection" do
201
- start_client( rpc_opts_with_mixed_ssl_primitives ).call( 'test.foo', @arg ){
202
- |res|
183
+ start_client( rpc_opts_with_mixed_ssl_primitives ).call( 'test.foo', @arg ) do |res|
203
184
  res.rpc_connection_error?.should be_true
204
185
  res.rpc_ssl_error?.should be_true
205
186
  ::EM.stop
206
- }
207
- Arachni::RPC::EM.block!
187
+ end
188
+ Arachni::RPC::EM.block
208
189
  end
209
190
  end
210
191
 
@@ -8,8 +8,8 @@ end
8
8
  describe Arachni::RPC::EM::Server do
9
9
 
10
10
  before( :all ) do
11
- @opts = rpc_opts.merge( :port => 7333 )
12
- @server, t = start_server( @opts )
11
+ @opts = rpc_opts.merge( port: 7333 )
12
+ @server = start_server( @opts, true )
13
13
  end
14
14
 
15
15
  describe "#initialize" do
@@ -1,3 +1,6 @@
1
1
  require_relative 'server'
2
2
 
3
- start_server( rpc_opts )[1].join
3
+ $stdout.reopen( '/dev/null', 'w' )
4
+ $stderr.reopen( '/dev/null', 'w' )
5
+
6
+ start_server( rpc_opts )
@@ -10,11 +10,42 @@
10
10
 
11
11
  $cwd = cwd = File.expand_path( File.dirname( __FILE__ ) )
12
12
  require File.join( cwd, '../../lib/arachni/rpc/', 'em' )
13
- require File.join( cwd, '../', 'spec_helper' )
13
+
14
+ def rpc_opts
15
+ {
16
+ host: 'localhost',
17
+ port: 7331,
18
+ token: 'superdupersecret',
19
+ serializer: Marshal,
20
+ }
21
+ end
22
+
23
+ def rpc_opts_with_ssl_primitives
24
+ rpc_opts.merge(
25
+ port: 7332,
26
+ ssl_ca: cwd + '/pems/cacert.pem',
27
+ ssl_pkey: cwd + '/pems/client/key.pem',
28
+ ssl_cert: cwd + '/pems/client/cert.pem'
29
+ )
30
+ end
31
+
32
+ def rpc_opts_with_invalid_ssl_primitives
33
+ rpc_opts_with_ssl_primitives.merge(
34
+ ssl_pkey: cwd + '/pems/client/foo-key.pem',
35
+ ssl_cert: cwd + '/pems/client/foo-cert.pem'
36
+ )
37
+ end
38
+
39
+ def rpc_opts_with_mixed_ssl_primitives
40
+ rpc_opts_with_ssl_primitives.merge(
41
+ ssl_pkey: cwd + '/pems/client/key.pem',
42
+ ssl_cert: cwd + '/pems/client/foo-cert.pem'
43
+ )
44
+ end
14
45
 
15
46
  class Parent
16
47
  def foo( arg )
17
- return arg
48
+ arg
18
49
  end
19
50
  end
20
51
 
@@ -23,39 +54,21 @@ class Test < Parent
23
54
  # in order to make inherited methods accessible you've got to explicitly
24
55
  # make them public
25
56
  private :foo
26
- public :foo
57
+ public :foo
27
58
 
28
59
  #
29
60
  # Uses EventMachine to call the block asynchronously
30
61
  #
31
62
  def async_foo( arg, &block )
32
- ::EM.schedule {
33
- ::EM.defer {
34
- block.call( arg ) if block_given?
35
- }
36
- }
63
+ ::EM.schedule { ::EM.defer { block.call( arg ) if block_given? } }
37
64
  end
38
65
 
39
66
  end
40
67
 
41
68
  def start_server( opts, do_not_start = false )
42
-
43
69
  server = Arachni::RPC::EM::Server.new( opts )
44
-
45
- server.add_async_check {
46
- |method|
47
- #
48
- # Must return 'true' for async and 'false' for sync.
49
- #
50
- # Very simple check here...
51
- #
52
- 'async' == method.name.to_s.split( '_' )[0]
53
- }
54
-
70
+ server.add_async_check { |method| method.name.to_s.start_with?( 'async_' ) }
55
71
  server.add_handler( 'test', Test.new )
56
-
57
- t = nil
58
- t = Thread.new { server.run } if !do_not_start
59
-
60
- return server, t
72
+ server.run if !do_not_start
73
+ server
61
74
  end
@@ -1,5 +1,8 @@
1
1
  require_relative 'server'
2
2
 
3
+ $stdout.reopen( '/dev/null', 'w' )
4
+ $stderr.reopen( '/dev/null', 'w' )
5
+
3
6
  cwd = File.expand_path( File.dirname( __FILE__ ) )
4
7
  opts = rpc_opts.merge(
5
8
  :port => 7332,
@@ -8,4 +11,4 @@ opts = rpc_opts.merge(
8
11
  :ssl_cert => cwd + '/../pems/server/cert.pem'
9
12
  )
10
13
 
11
- start_server( opts )[1].join
14
+ start_server( opts )
data/spec/spec_helper.rb CHANGED
@@ -1,4 +1,4 @@
1
-
1
+ require 'rspec'
2
2
  require 'timeout'
3
3
 
4
4
  def cwd
@@ -8,39 +8,35 @@ end
8
8
  require File.join( cwd, '../lib/arachni/rpc/', 'em' )
9
9
  require File.join( cwd, 'servers', 'server' )
10
10
 
11
- def rpc_opts
12
- {
13
- :host => 'localhost',
14
- :port => 7331,
15
- :token => 'superdupersecret',
16
- :serializer => Marshal,
17
- }
18
- end
19
-
20
- def rpc_opts_with_ssl_primitives
21
- rpc_opts.merge(
22
- :port => 7332,
23
- :ssl_ca => cwd + '/pems/cacert.pem',
24
- :ssl_pkey => cwd + '/pems/client/key.pem',
25
- :ssl_cert => cwd + '/pems/client/cert.pem'
26
- )
11
+ def start_client( opts )
12
+ Arachni::RPC::EM::Client.new( opts )
27
13
  end
28
14
 
29
- def rpc_opts_with_invalid_ssl_primitives
30
- rpc_opts_with_ssl_primitives.merge(
31
- :ssl_pkey => cwd + '/pems/client/foo-key.pem',
32
- :ssl_cert => cwd + '/pems/client/foo-cert.pem'
33
- )
15
+ def quiet_fork( &block )
16
+ fork {
17
+ $stdout.reopen( '/dev/null', 'w' )
18
+ $stderr.reopen( '/dev/null', 'w' )
19
+ block.call
20
+ }
34
21
  end
35
22
 
36
- def rpc_opts_with_mixed_ssl_primitives
37
- rpc_opts_with_ssl_primitives.merge(
38
- :ssl_pkey => cwd + '/pems/client/key.pem',
39
- :ssl_cert => cwd + '/pems/client/foo-cert.pem'
40
- )
23
+ def quiet_spawn( file )
24
+ Process.spawn 'ruby ' + file
41
25
  end
42
26
 
43
-
44
- def start_client( opts )
45
- Arachni::RPC::EM::Client.new( opts )
27
+ server_pids = []
28
+ RSpec.configure do |config|
29
+ config.color = true
30
+ config.add_formatter :documentation
31
+
32
+ config.before( :suite ) do
33
+ server_pids << quiet_spawn( File.join( cwd, 'servers', 'basic.rb' ) )
34
+ server_pids << quiet_spawn( File.join( cwd, 'servers', 'with_ssl_primitives.rb' ) )
35
+ server_pids.each { |pid| Process.detach( pid ) }
36
+ sleep 2
37
+ end
38
+
39
+ config.after( :suite ) do
40
+ server_pids.each { |pid| Process.kill( 'KILL', pid ) }
41
+ end
46
42
  end
metadata CHANGED
@@ -1,7 +1,7 @@
1
1
  --- !ruby/object:Gem::Specification
2
2
  name: arachni-rpc-em
3
3
  version: !ruby/object:Gem::Version
4
- version: 0.1.1
4
+ version: 0.1.2
5
5
  prerelease:
6
6
  platform: ruby
7
7
  authors:
@@ -9,11 +9,11 @@ authors:
9
9
  autorequire:
10
10
  bindir: bin
11
11
  cert_chain: []
12
- date: 2011-12-28 00:00:00.000000000 Z
12
+ date: 2012-08-23 00:00:00.000000000 Z
13
13
  dependencies:
14
14
  - !ruby/object:Gem::Dependency
15
15
  name: eventmachine
16
- requirement: &17576520 !ruby/object:Gem::Requirement
16
+ requirement: !ruby/object:Gem::Requirement
17
17
  none: false
18
18
  requirements:
19
19
  - - ! '>='
@@ -21,10 +21,15 @@ dependencies:
21
21
  version: 1.0.0.beta.4
22
22
  type: :runtime
23
23
  prerelease: false
24
- version_requirements: *17576520
24
+ version_requirements: !ruby/object:Gem::Requirement
25
+ none: false
26
+ requirements:
27
+ - - ! '>='
28
+ - !ruby/object:Gem::Version
29
+ version: 1.0.0.beta.4
25
30
  - !ruby/object:Gem::Dependency
26
31
  name: em-synchrony
27
- requirement: &17576020 !ruby/object:Gem::Requirement
32
+ requirement: !ruby/object:Gem::Requirement
28
33
  none: false
29
34
  requirements:
30
35
  - - ! '>='
@@ -32,18 +37,28 @@ dependencies:
32
37
  version: 1.0.0
33
38
  type: :runtime
34
39
  prerelease: false
35
- version_requirements: *17576020
40
+ version_requirements: !ruby/object:Gem::Requirement
41
+ none: false
42
+ requirements:
43
+ - - ! '>='
44
+ - !ruby/object:Gem::Version
45
+ version: 1.0.0
36
46
  - !ruby/object:Gem::Dependency
37
47
  name: arachni-rpc
38
- requirement: &17575540 !ruby/object:Gem::Requirement
48
+ requirement: !ruby/object:Gem::Requirement
39
49
  none: false
40
50
  requirements:
41
- - - =
51
+ - - '='
42
52
  - !ruby/object:Gem::Version
43
- version: 0.1.1
53
+ version: 0.1.2
44
54
  type: :runtime
45
55
  prerelease: false
46
- version_requirements: *17575540
56
+ version_requirements: !ruby/object:Gem::Requirement
57
+ none: false
58
+ requirements:
59
+ - - '='
60
+ - !ruby/object:Gem::Version
61
+ version: 0.1.2
47
62
  description: ! " EventMachine-based client and server implementation of Arachni-RPC
48
63
  supporting\n TLS encryption, asynchronous and synchronous requests and\n
49
64
  \ capable of handling remote asynchronous calls that require a block.\n"
@@ -59,33 +74,32 @@ files:
59
74
  - Rakefile
60
75
  - LICENSE.md
61
76
  - CHANGELOG.md
62
- - lib/arachni/rpc/em.rb
63
- - lib/arachni/rpc/em/protocol.rb
64
- - lib/arachni/rpc/em/ssl.rb
65
77
  - lib/arachni/rpc/em/version.rb
66
- - lib/arachni/rpc/em/connection_utilities.rb
67
78
  - lib/arachni/rpc/em/em.rb
68
79
  - lib/arachni/rpc/em/client.rb
69
80
  - lib/arachni/rpc/em/server.rb
81
+ - lib/arachni/rpc/em/protocol.rb
82
+ - lib/arachni/rpc/em/connection_utilities.rb
83
+ - lib/arachni/rpc/em/ssl.rb
84
+ - lib/arachni/rpc/em.rb
85
+ - examples/client.EM.run.rb
70
86
  - examples/client.rb
71
87
  - examples/server.rb
72
- - examples/client.EM.run.rb
73
- - spec/servers/with_ssl_primitives.rb
74
- - spec/servers/basic.rb
75
- - spec/servers/server.rb
76
- - spec/spec_helper.rb
77
- - spec/arachni/rpc/em/server_spec.rb
78
- - spec/arachni/rpc/em/ssl_spec.rb
79
- - spec/arachni/rpc/em/em_spec.rb
80
- - spec/arachni/rpc/em/client_spec.rb
81
88
  - spec/pems/cacert.pem
82
89
  - spec/pems/server/key.pem
83
90
  - spec/pems/server/cert.pem
84
- - spec/pems/client/key.pem
85
91
  - spec/pems/client/foo-cert.pem
86
92
  - spec/pems/client/foo-key.pem
93
+ - spec/pems/client/key.pem
87
94
  - spec/pems/client/cert.pem
88
- - spec/spec.opts
95
+ - spec/arachni/rpc/em/em_spec.rb
96
+ - spec/arachni/rpc/em/server_spec.rb
97
+ - spec/arachni/rpc/em/client_spec.rb
98
+ - spec/arachni/rpc/em/ssl_spec.rb
99
+ - spec/spec_helper.rb
100
+ - spec/servers/server.rb
101
+ - spec/servers/basic.rb
102
+ - spec/servers/with_ssl_primitives.rb
89
103
  homepage: https://github.com/Arachni/arachni-rpc
90
104
  licenses: []
91
105
  post_install_message:
@@ -107,28 +121,23 @@ required_rubygems_version: !ruby/object:Gem::Requirement
107
121
  version: '0'
108
122
  requirements: []
109
123
  rubyforge_project:
110
- rubygems_version: 1.8.10
124
+ rubygems_version: 1.8.24
111
125
  signing_key:
112
126
  specification_version: 3
113
127
  summary: The RPC client and server used by the Arachni WebAppSec scanner Grid.
114
128
  test_files:
115
- - examples/client.rb
116
- - examples/server.rb
117
- - examples/client.EM.run.rb
118
- - spec/servers/with_ssl_primitives.rb
119
- - spec/servers/basic.rb
120
- - spec/servers/server.rb
121
- - spec/spec_helper.rb
122
- - spec/arachni/rpc/em/server_spec.rb
123
- - spec/arachni/rpc/em/ssl_spec.rb
124
- - spec/arachni/rpc/em/em_spec.rb
125
- - spec/arachni/rpc/em/client_spec.rb
126
129
  - spec/pems/cacert.pem
127
130
  - spec/pems/server/key.pem
128
131
  - spec/pems/server/cert.pem
129
- - spec/pems/client/key.pem
130
132
  - spec/pems/client/foo-cert.pem
131
133
  - spec/pems/client/foo-key.pem
134
+ - spec/pems/client/key.pem
132
135
  - spec/pems/client/cert.pem
133
- - spec/spec.opts
134
- has_rdoc:
136
+ - spec/arachni/rpc/em/em_spec.rb
137
+ - spec/arachni/rpc/em/server_spec.rb
138
+ - spec/arachni/rpc/em/client_spec.rb
139
+ - spec/arachni/rpc/em/ssl_spec.rb
140
+ - spec/spec_helper.rb
141
+ - spec/servers/server.rb
142
+ - spec/servers/basic.rb
143
+ - spec/servers/with_ssl_primitives.rb
data/spec/spec.opts DELETED
@@ -1,2 +0,0 @@
1
- --color
2
- --backtrace