dizby 1.3.0
Sign up to get free protection for your applications and to get access to all the features.
- 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
|