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.
- checksums.yaml +7 -0
- data/.rubocop.yml +10 -0
- data/LICENSE +24 -0
- data/dizby.gemspec +27 -0
- data/lib/dizby.rb +12 -0
- data/lib/dizby/access/control_list.rb +78 -0
- data/lib/dizby/access/entry.rb +61 -0
- data/lib/dizby/access/insecure.rb +30 -0
- data/lib/dizby/access/list.rb +10 -0
- data/lib/dizby/converter/simple.rb +12 -0
- data/lib/dizby/converter/timed.rb +23 -0
- data/lib/dizby/distributed/array.rb +30 -0
- data/lib/dizby/distributed/object.rb +44 -0
- data/lib/dizby/distributed/proxy.rb +41 -0
- data/lib/dizby/distributed/semi_proxy.rb +26 -0
- data/lib/dizby/distributed/undumpable.rb +8 -0
- data/lib/dizby/distributed/unknown.rb +57 -0
- data/lib/dizby/error.rb +29 -0
- data/lib/dizby/protocol/basic.rb +31 -0
- data/lib/dizby/protocol/manager.rb +62 -0
- data/lib/dizby/protocol/refined.rb +23 -0
- data/lib/dizby/protocols/dead.rb +24 -0
- data/lib/dizby/protocols/secure.rb +87 -0
- data/lib/dizby/protocols/tcp.rb +98 -0
- data/lib/dizby/protocols/unix.rb +95 -0
- data/lib/dizby/server/abstract.rb +42 -0
- data/lib/dizby/server/basic.rb +101 -0
- data/lib/dizby/server/registration.rb +23 -0
- data/lib/dizby/service.rb +64 -0
- data/lib/dizby/stream/client.rb +26 -0
- data/lib/dizby/stream/connection.rb +63 -0
- data/lib/dizby/stream/messenger.rb +28 -0
- data/lib/dizby/stream/query_ref.rb +13 -0
- data/lib/dizby/stream/readable.rb +65 -0
- data/lib/dizby/stream/writable.rb +37 -0
- data/lib/dizby/tunnel/abstract.rb +52 -0
- data/lib/dizby/tunnel/basic.rb +21 -0
- data/lib/dizby/tunnel/basic_spawn.rb +50 -0
- data/lib/dizby/tunnel/bidirectional_strategy.rb +29 -0
- data/lib/dizby/tunnel/factory.rb +29 -0
- data/lib/dizby/tunnel/local_strategy.rb +24 -0
- data/lib/dizby/tunnel/spawn_command.rb +49 -0
- data/lib/dizby/tunnel/spawned.rb +43 -0
- data/lib/dizby/tunnel/tunnelable_local.rb +8 -0
- data/lib/dizby/tunnel/tunnelable_remote.rb +21 -0
- data/lib/dizby/utility/classic_access.rb +25 -0
- data/lib/dizby/utility/configurable.rb +25 -0
- data/lib/dizby/utility/delegator.rb +28 -0
- data/lib/dizby/utility/io_barrier.rb +18 -0
- data/lib/dizby/utility/log.rb +23 -0
- data/lib/dizby/utility/monitor.rb +9 -0
- data/lib/dizby/utility/polymorphic_delegated.rb +58 -0
- data/lib/dizby/utility/self_pipe.rb +12 -0
- data/lib/dizby/utility/semi_built.rb +17 -0
- data/lib/dizby/utility/string.rb +8 -0
- data/lib/dizby/utility/timed_collection.rb +39 -0
- data/lib/dizby/utility/timed_state.rb +41 -0
- data/lib/dizby/version.rb +4 -0
- data/lib/dizby/worker/connection.rb +44 -0
- data/lib/dizby/worker/invoke_method.rb +55 -0
- data/lib/dizby/worker/server.rb +39 -0
- 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,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
|