dizby 1.3.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.
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