dizby 1.3.0

Sign up to get free protection for your applications and to get access to all the features.
Files changed (62) hide show
  1. checksums.yaml +7 -0
  2. data/.rubocop.yml +10 -0
  3. data/LICENSE +24 -0
  4. data/dizby.gemspec +27 -0
  5. data/lib/dizby.rb +12 -0
  6. data/lib/dizby/access/control_list.rb +78 -0
  7. data/lib/dizby/access/entry.rb +61 -0
  8. data/lib/dizby/access/insecure.rb +30 -0
  9. data/lib/dizby/access/list.rb +10 -0
  10. data/lib/dizby/converter/simple.rb +12 -0
  11. data/lib/dizby/converter/timed.rb +23 -0
  12. data/lib/dizby/distributed/array.rb +30 -0
  13. data/lib/dizby/distributed/object.rb +44 -0
  14. data/lib/dizby/distributed/proxy.rb +41 -0
  15. data/lib/dizby/distributed/semi_proxy.rb +26 -0
  16. data/lib/dizby/distributed/undumpable.rb +8 -0
  17. data/lib/dizby/distributed/unknown.rb +57 -0
  18. data/lib/dizby/error.rb +29 -0
  19. data/lib/dizby/protocol/basic.rb +31 -0
  20. data/lib/dizby/protocol/manager.rb +62 -0
  21. data/lib/dizby/protocol/refined.rb +23 -0
  22. data/lib/dizby/protocols/dead.rb +24 -0
  23. data/lib/dizby/protocols/secure.rb +87 -0
  24. data/lib/dizby/protocols/tcp.rb +98 -0
  25. data/lib/dizby/protocols/unix.rb +95 -0
  26. data/lib/dizby/server/abstract.rb +42 -0
  27. data/lib/dizby/server/basic.rb +101 -0
  28. data/lib/dizby/server/registration.rb +23 -0
  29. data/lib/dizby/service.rb +64 -0
  30. data/lib/dizby/stream/client.rb +26 -0
  31. data/lib/dizby/stream/connection.rb +63 -0
  32. data/lib/dizby/stream/messenger.rb +28 -0
  33. data/lib/dizby/stream/query_ref.rb +13 -0
  34. data/lib/dizby/stream/readable.rb +65 -0
  35. data/lib/dizby/stream/writable.rb +37 -0
  36. data/lib/dizby/tunnel/abstract.rb +52 -0
  37. data/lib/dizby/tunnel/basic.rb +21 -0
  38. data/lib/dizby/tunnel/basic_spawn.rb +50 -0
  39. data/lib/dizby/tunnel/bidirectional_strategy.rb +29 -0
  40. data/lib/dizby/tunnel/factory.rb +29 -0
  41. data/lib/dizby/tunnel/local_strategy.rb +24 -0
  42. data/lib/dizby/tunnel/spawn_command.rb +49 -0
  43. data/lib/dizby/tunnel/spawned.rb +43 -0
  44. data/lib/dizby/tunnel/tunnelable_local.rb +8 -0
  45. data/lib/dizby/tunnel/tunnelable_remote.rb +21 -0
  46. data/lib/dizby/utility/classic_access.rb +25 -0
  47. data/lib/dizby/utility/configurable.rb +25 -0
  48. data/lib/dizby/utility/delegator.rb +28 -0
  49. data/lib/dizby/utility/io_barrier.rb +18 -0
  50. data/lib/dizby/utility/log.rb +23 -0
  51. data/lib/dizby/utility/monitor.rb +9 -0
  52. data/lib/dizby/utility/polymorphic_delegated.rb +58 -0
  53. data/lib/dizby/utility/self_pipe.rb +12 -0
  54. data/lib/dizby/utility/semi_built.rb +17 -0
  55. data/lib/dizby/utility/string.rb +8 -0
  56. data/lib/dizby/utility/timed_collection.rb +39 -0
  57. data/lib/dizby/utility/timed_state.rb +41 -0
  58. data/lib/dizby/version.rb +4 -0
  59. data/lib/dizby/worker/connection.rb +44 -0
  60. data/lib/dizby/worker/invoke_method.rb +55 -0
  61. data/lib/dizby/worker/server.rb +39 -0
  62. metadata +146 -0
@@ -0,0 +1,42 @@
1
+
2
+ require 'dizby/protocol/manager'
3
+ require 'dizby/distributed/object'
4
+ require 'dizby/utility/configurable'
5
+ require 'dizby/utility/log'
6
+
7
+ module Dizby
8
+ class AbstractServer
9
+ extend Configurable
10
+
11
+ def initialize(config, &log_transform)
12
+ @config = config
13
+ @log = Dizby.create_logger(config[:logging], &log_transform)
14
+ end
15
+
16
+ attr_reader :log
17
+ config_reader :load_limit
18
+
19
+ def connect_to(uri)
20
+ ProtocolManager.open_client(self, uri)
21
+ end
22
+
23
+ def spawn_on(command, uri)
24
+ ProtocolManager.spawn_server(self, command, uri)
25
+ end
26
+
27
+ def shutdown; end
28
+
29
+ def alive?
30
+ true
31
+ end
32
+
33
+ def make_distributed(obj, error)
34
+ if error
35
+ RemoteDistributedError.new(obj)
36
+ else
37
+ log.debug("making distributed: #{obj.inspect}")
38
+ DistributedObject.new(obj, self)
39
+ end
40
+ end
41
+ end
42
+ end
@@ -0,0 +1,101 @@
1
+
2
+ require 'dizby/stream/query_ref'
3
+ require 'dizby/utility/polymorphic_delegated'
4
+ require 'dizby/utility/self_pipe'
5
+ require 'dizby/utility/monitor'
6
+
7
+ require 'io/wait'
8
+
9
+ module Dizby
10
+ class BasicServer < AbstractServer
11
+ extend ClassicAttributeAccess
12
+
13
+ def initialize(uri, front, stream, config)
14
+ super(config) { |msg| "#{uri} : #{msg}" }
15
+
16
+ @uri = uri
17
+ @front = front
18
+ @stream = stream
19
+
20
+ @exported_uri = Dizby.monitor([@uri])
21
+
22
+ @shutdown_pipe = SelfPipe.new(*IO.pipe)
23
+ end
24
+
25
+ def close
26
+ log.debug('Closing')
27
+ if stream
28
+ stream.close
29
+ self.stream = nil
30
+ end
31
+
32
+ close_shutdown_pipe
33
+ end
34
+
35
+ def shutdown
36
+ log.debug('Shutting down')
37
+ shutdown_pipe.close_write if shutdown_pipe
38
+ end
39
+
40
+ def accept
41
+ readables, = IO.select([stream, shutdown_pipe.read])
42
+ fail LocalServerShutdown if readables.include? shutdown_pipe.read
43
+ log.debug('Accepting connection')
44
+ stream.accept
45
+ end
46
+
47
+ def alive?
48
+ return false unless stream
49
+ return true if stream.ready?
50
+
51
+ shutdown
52
+ false
53
+ end
54
+
55
+ def to_obj(ref)
56
+ case ref
57
+ when nil
58
+ front
59
+ when QueryRef
60
+ front[ref.to_s]
61
+ else
62
+ idconv.to_obj(ref)
63
+ end
64
+ end
65
+
66
+ def to_id(obj)
67
+ return nil if obj.__id__ == front.__id__
68
+ idconv.to_id(obj)
69
+ end
70
+
71
+ attr_reader :uri
72
+ config_reader :argc_limit
73
+
74
+ def add_uri_alias(uri)
75
+ log.debug("Adding uri alias: #{uri}")
76
+
77
+ exported_uri.synchronize do
78
+ exported_uri << uri unless exported_uri.include?(uri)
79
+ end
80
+ end
81
+
82
+ def here?(uri)
83
+ exported_uri.synchronize { exported_uri.include?(uri) }
84
+ end
85
+
86
+ private
87
+
88
+ config_reader :idconv
89
+ attr_reader :front, :exported_uri
90
+ attr_accessor :stream, :shutdown_pipe
91
+
92
+ def close_shutdown_pipe
93
+ return nil unless shutdown_pipe
94
+
95
+ log.debug('Closing shutdown pipe')
96
+ shutdown_pipe.close_read
97
+ shutdown_pipe.close_write
98
+ self.shutdown_pipe = nil
99
+ end
100
+ end
101
+ end
@@ -0,0 +1,23 @@
1
+
2
+ require 'dizby/utility/monitor'
3
+
4
+ module Dizby
5
+ @servers = Dizby.monitor([])
6
+
7
+ def self.register_server(server)
8
+ @servers.synchronize { @servers << server }
9
+ end
10
+
11
+ def self.unregister_server(server)
12
+ @servers.synchronize { @servers.delete(server) }
13
+ end
14
+
15
+ # returns [success, object]
16
+ def self.get_obj(uri, ref)
17
+ @servers.synchronize do
18
+ local_server = @servers.find { |server| server && server.here?(uri) }
19
+
20
+ [!local_server.nil?, local_server && local_server.to_obj(ref)]
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,64 @@
1
+
2
+ require 'dizby/protocol/manager'
3
+ require 'dizby/converter/simple'
4
+ require 'dizby/worker/server'
5
+ require 'dizby/utility/log'
6
+
7
+ module Dizby
8
+ class Service
9
+ def initialize(uri = '', front = nil, config = {})
10
+ config = DEFAULT_CONFIG.merge(config)
11
+
12
+ self.server = ProtocolManager.open_server(uri, front, config)
13
+ rescue NonAcceptingServer => err
14
+ # This is to allow servers that don't accept connections
15
+ # Not all servers will allow connections back to them, so don't allow it
16
+ self.server = err.server
17
+ @server.log.warn('using a server that does not allow connections')
18
+ else
19
+ @worker = ServiceWorker.new(@server)
20
+ ensure
21
+ Dizby.register_server(@server)
22
+ end
23
+
24
+ def connect_to(uri)
25
+ ObjectProxy.new(*@server.connect_to(uri))
26
+ end
27
+
28
+ def spawn_on(command, uri)
29
+ ObjectProxy.new(*@server.spawn_on(command, uri))
30
+ end
31
+
32
+ def close
33
+ Dizby.unregister_server @server
34
+ return unless alive?
35
+ @server.shutdown
36
+ end
37
+
38
+ def alive?
39
+ @server.alive?
40
+ end
41
+
42
+ def wait
43
+ @worker.join if @worker
44
+ end
45
+
46
+ DEFAULT_CONFIG = {
47
+ idconv: IdConverter,
48
+ argc_limit: 256,
49
+ load_limit: 256 * 1024 * 100,
50
+ logging: {
51
+ level: Logger::ERROR,
52
+ output: $stderr
53
+ },
54
+ tcp_acl: nil
55
+ }
56
+
57
+ private
58
+
59
+ def server=(srvr)
60
+ fail DistributedError, 'server could not be opened' unless srvr
61
+ @server = srvr
62
+ end
63
+ end
64
+ end
@@ -0,0 +1,26 @@
1
+
2
+ require 'dizby/stream/messenger'
3
+
4
+ module Dizby
5
+ class BasicClient < Messenger
6
+ def initialize(server, stream, remote_uri)
7
+ super(server, stream)
8
+
9
+ @remote_uri = remote_uri
10
+
11
+ # write the other side's remote_uri to the socket
12
+ write(dump_data(@remote_uri))
13
+ end
14
+
15
+ def send_request(ref, msg_id, *args, &block)
16
+ arr = [ref, msg_id.id2name, args.length, *args, block]
17
+ arr.map! { |ele| dump_data(ele) }
18
+ write(arr.join(''))
19
+ end
20
+
21
+ def recv_reply
22
+ succ, result = 2.times.map { read }
23
+ [succ, result]
24
+ end
25
+ end
26
+ end
@@ -0,0 +1,63 @@
1
+
2
+ require 'dizby/stream/messenger'
3
+ require 'dizby/utility/self_pipe'
4
+
5
+ module Dizby
6
+ class BasicConnection < Messenger
7
+ def initialize(server, stream)
8
+ super(server, stream)
9
+
10
+ # get the uri that the client recognizes the server as
11
+ @remote_uri = read
12
+
13
+ @shutdown_pipe = SelfPipe.new(*IO.pipe)
14
+ @object_space = []
15
+ end
16
+
17
+ def recv_request
18
+ wait_for_stream
19
+
20
+ ref, msg, argc = 3.times.map { read }
21
+
22
+ @server.log.debug("called through proxy: #{ref} #{msg}")
23
+ fail ConnectionError, 'too many arguments' if @server.argc_limit < argc
24
+
25
+ argv = Array.new(argc) { read }
26
+ block = read
27
+
28
+ ro = @server.to_obj(ref)
29
+ [ro, msg, argv, block]
30
+ end
31
+
32
+ def send_reply(succ, result)
33
+ write(dump_data(succ) + dump_data(result, !succ))
34
+ rescue
35
+ raise ConnectionError, $!.message, $!.backtrace
36
+ end
37
+
38
+ def close
39
+ @object_space.clear
40
+ shutdown_pipe.close_write if shutdown_pipe
41
+ super
42
+ end
43
+
44
+ private
45
+
46
+ # when a distributed object is made through a connection, store it
47
+ # so that it doesn't get consumed by the garbage collector
48
+ def make_distributed(_obj, _error)
49
+ distributed = super
50
+ @object_space << distributed
51
+ distributed
52
+ end
53
+
54
+ def wait_for_stream
55
+ readable, = IO.select([@stream, shutdown_pipe.read])
56
+ fail RemoteServerShutdown if readable.include?(shutdown_pipe.read)
57
+ rescue IOError
58
+ raise RemoteServerShutdown
59
+ end
60
+
61
+ attr_reader :shutdown_pipe
62
+ end
63
+ end
@@ -0,0 +1,28 @@
1
+
2
+ require 'dizby/stream/readable'
3
+ require 'dizby/stream/writable'
4
+
5
+ module Dizby
6
+ class Messenger
7
+ include ReadableStream
8
+ include WritableStream
9
+
10
+ def initialize(server, stream)
11
+ @server = server
12
+
13
+ # stream needs to have the read(int), write(str), and close() methods
14
+ # this value can be overloaded in the client/server classes for a protocol
15
+ @stream = stream
16
+ end
17
+
18
+ attr_reader :server, :remote_uri
19
+
20
+ def close
21
+ @stream.close
22
+ end
23
+
24
+ def closed?
25
+ !@stream || @stream.closed?
26
+ end
27
+ end
28
+ end
@@ -0,0 +1,13 @@
1
+
2
+ module Dizby
3
+ # Acts as an array or hash index to a remote object
4
+ class QueryRef
5
+ def initialize(query)
6
+ @query = query
7
+ end
8
+
9
+ def to_s
10
+ @query.to_s
11
+ end
12
+ end
13
+ end
@@ -0,0 +1,65 @@
1
+
2
+ require 'dizby/distributed/semi_proxy'
3
+
4
+ module Dizby
5
+ module ReadableStream
6
+ def read
7
+ sz = check_packet_size(load_size)
8
+ str = load_packet(sz)
9
+
10
+ fail ConnectionError, 'connection closed' unless str
11
+
12
+ if str.size < sz
13
+ fail ConnectionError, 'premature marshal format(can\'t read)'
14
+ end
15
+
16
+ load_obj(str)
17
+
18
+ # TODO: un-tainting???
19
+ end
20
+
21
+ private
22
+
23
+ def load_size
24
+ @stream.read(4)
25
+ rescue
26
+ raise ConnectionError, $!.message, $!.backtrace
27
+ end
28
+
29
+ def load_packet(sz)
30
+ @stream.read(sz)
31
+ rescue
32
+ raise ConnectionError, $!.message, $!.backtrace
33
+ end
34
+
35
+ def load_obj(marshalled_str)
36
+ @server.log.debug("loading data: #{marshalled_str.inspect}")
37
+ obj = Marshal.load(marshalled_str)
38
+ @server.log.debug("loaded: #{obj.inspect}")
39
+
40
+ # get a local object or create the proxy using the current server
41
+ # done here since marshalling doesn't know about the current server
42
+ obj = obj.evaluate(@server) if obj.is_a?(SemiObjectProxy)
43
+
44
+ obj
45
+ rescue NameError, ArgumentError
46
+ @server.log.debug("unknown: #{$!.inspect} #{$!.backtrace}")
47
+ UnknownObject.new($!, marshalled_str)
48
+ end
49
+
50
+ def check_packet_size(sz)
51
+ fail RemoteServerShutdown unless sz
52
+ fail ConnectionError, 'premature header' if sz.size < 4
53
+
54
+ sz = sz.unpack('N')[0]
55
+
56
+ # load_limit must be greater than the size of the packet
57
+ # or the load_limit can be 0 or less to be considered "infinite"
58
+ if @server.load_limit.between?(0, sz)
59
+ fail ConnectionError, "too large packet for #{sz}"
60
+ end
61
+
62
+ sz
63
+ end
64
+ end
65
+ end
@@ -0,0 +1,37 @@
1
+
2
+ require 'dizby/distributed/undumpable'
3
+
4
+ module Dizby
5
+ module WritableStream
6
+ def write(data)
7
+ @stream.write(data)
8
+ end
9
+
10
+ def dump_data(obj, error = false)
11
+ @server.log.debug("dumping: #{obj.inspect}")
12
+
13
+ if obj.is_a?(UndumpableObject)
14
+ @server.log.debug('dumping undumpable')
15
+ obj = make_distributed(obj, error)
16
+ end
17
+
18
+ str = dump_obj(obj, error)
19
+ @server.log.debug("dumped: #{str.inspect}")
20
+
21
+ [str.size].pack('N') + str
22
+ end
23
+
24
+ private
25
+
26
+ def dump_obj(obj, error)
27
+ Marshal.dump(obj)
28
+ rescue
29
+ @server.log.debug('rescuing and dumping pseudo-undumpable...')
30
+ Marshal.dump(make_distributed(obj, error))
31
+ end
32
+
33
+ def make_distributed(obj, error)
34
+ @server.make_distributed(obj, error)
35
+ end
36
+ end
37
+ end