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,8 @@
1
+
2
+ module Dizby
3
+ module UndumpableObject
4
+ def _dump(_)
5
+ fail TypeError, 'can\'t dump'
6
+ end
7
+ end
8
+ end
@@ -0,0 +1,57 @@
1
+
2
+ require 'dizby/error'
3
+
4
+ module Dizby
5
+ class UnknownObject
6
+ def initialize(err, buf)
7
+ case err.to_s
8
+ when /uninitialized constant (\S+)/
9
+ @name = $~[1]
10
+ when %r{undefined class/module (\S+)}
11
+ @name = $~[1]
12
+ else
13
+ @name = nil
14
+ end
15
+
16
+ @buf = buf
17
+ end
18
+
19
+ attr_reader :name, :buf
20
+
21
+ def self._load(str)
22
+ Marshal.load(str)
23
+ rescue NameError, ArgumentError
24
+ UnknownObject.new($!, str)
25
+ end
26
+
27
+ def _dump(_)
28
+ Marshal.dump(@buf)
29
+ end
30
+
31
+ def reload
32
+ self.class._load @buf
33
+ end
34
+
35
+ def exception
36
+ UnknownObjectError.new self
37
+ end
38
+ end
39
+
40
+ class UnknownObjectError < DistributedError
41
+ def initialize(unknown)
42
+ @unknown = unknown
43
+ super unknown.name
44
+ end
45
+
46
+ # give access to the UnknownObject class
47
+ attr_reader :unknown
48
+
49
+ def self._load(str)
50
+ Marshal.load(str)
51
+ end
52
+
53
+ def _dump(_)
54
+ Marshal.dump(@unknown)
55
+ end
56
+ end
57
+ end
@@ -0,0 +1,29 @@
1
+
2
+ module Dizby
3
+ class DistributedError < RuntimeError; end
4
+ class ConnectionError < DistributedError; end
5
+ class ServerNotFound < DistributedError; end
6
+ class BadURI < DistributedError; end
7
+ class BadScheme < DistributedError; end
8
+ class LocalServerShutdown < DistributedError; end
9
+ class RemoteServerShutdown < ConnectionError; end
10
+ class SpawnError < DistributedError; end
11
+
12
+ class NonAcceptingServer < DistributedError
13
+ def initialize(server)
14
+ @server = server
15
+ end
16
+
17
+ attr_reader :server
18
+ end
19
+
20
+ class RemoteDistributedError < DistributedError
21
+ def initialize(error)
22
+ @reason = error.class.to_s
23
+ super("#{error.message} (#{@reason})")
24
+ set_backtrace(error.backtrace)
25
+ end
26
+
27
+ attr_reader :reason
28
+ end
29
+ end
@@ -0,0 +1,31 @@
1
+
2
+ require 'dizby/protocol/manager'
3
+ require 'dizby/protocol/refined'
4
+
5
+ module Dizby
6
+ module BasicProtocol
7
+ module ClassMethods
8
+ attr_reader :scheme
9
+
10
+ def get_refinement(type)
11
+ instance_variable_get(:"@#{type}_refined")
12
+ rescue NameError
13
+ nil
14
+ end
15
+
16
+ protected
17
+
18
+ attr_writer :scheme
19
+
20
+ def refine(type, regex, &block)
21
+ refined = RefinedProtocol.new(regex, &block)
22
+ instance_variable_set(:"@#{type}_refined", refined)
23
+ end
24
+ end
25
+
26
+ def self.included(base)
27
+ base.extend ClassMethods
28
+ ProtocolManager.add_protocol(base)
29
+ end
30
+ end
31
+ end
@@ -0,0 +1,62 @@
1
+
2
+ require 'dizby/error'
3
+
4
+ module Dizby
5
+ class ProtocolManager
6
+ # TODO: all required portions of a Protocol class need to be documented
7
+ class << self
8
+ def add_protocol(klass)
9
+ @protocols << klass
10
+ end
11
+
12
+ def open_client(server, uri)
13
+ call_refined(uri, :client, server)
14
+ end
15
+
16
+ def open_server(uri, front, config)
17
+ call_refined(uri, :server, front, config)
18
+ end
19
+
20
+ def spawn_server(server, command, uri)
21
+ call_refined(uri, :spawn, server, command)
22
+ end
23
+
24
+ private
25
+
26
+ def call_refined(uri, refiner, *base_args)
27
+ klass = get_protocol(uri)
28
+ refined = refine_protocol(klass, refiner)
29
+ args = get_arguments(refined, uri)
30
+ refined.call(*base_args, args)
31
+ end
32
+
33
+ def get_protocol(uri)
34
+ scheme = '' if uri.empty?
35
+ scheme ||= uri.split(':').first
36
+ fail BadScheme, "can't retrieve scheme: #{uri}" unless scheme
37
+
38
+ protocol = @protocols.find { |klass| klass.scheme == scheme }
39
+ protocol || fail(BadScheme, "scheme not found: #{scheme}")
40
+ end
41
+
42
+ def refine_protocol(protocol, refinement)
43
+ refined = protocol.get_refinement(refinement)
44
+
45
+ unless refined
46
+ fail NotImplementedError,
47
+ "#{refinement} refinement not supported for #{protocol}"
48
+ end
49
+
50
+ refined
51
+ end
52
+
53
+ def get_arguments(refined, uri)
54
+ fail BadURI, "can't parse uri: #{uri}" unless refined.regex =~ uri
55
+
56
+ $~[1..-1]
57
+ end
58
+ end
59
+
60
+ @protocols = []
61
+ end
62
+ end
@@ -0,0 +1,23 @@
1
+
2
+ module Dizby
3
+ PROTOCOL_REGEX = {
4
+ user: '(?:(.+?)@)',
5
+ host: '(.*?)',
6
+ port: '(?::(\d+))',
7
+ file: '(.+?)',
8
+ query: '(?:\?(.*?))'
9
+ }
10
+
11
+ class RefinedProtocol
12
+ def initialize(regex, &block)
13
+ @regex = /^#{format(regex, Dizby::PROTOCOL_REGEX)}$/
14
+ @block = block
15
+ end
16
+
17
+ attr_reader :regex
18
+
19
+ def call(*args)
20
+ @block.call(*args)
21
+ end
22
+ end
23
+ end
@@ -0,0 +1,24 @@
1
+
2
+ require 'dizby/protocol/basic'
3
+ require 'dizby/server/abstract'
4
+
5
+ module Dizby
6
+ class DeadProtocol
7
+ include BasicProtocol
8
+
9
+ self.scheme = ''
10
+
11
+ refine(:server, '') do |_, config|
12
+ fail NonAcceptingServer, Server.new(config)
13
+ end
14
+
15
+ class Server < AbstractServer
16
+ # A DeadProtocol server doesn't allow backwards connections
17
+ # therefore, making a distributed object goes against that.
18
+ def make_distributed(*_)
19
+ fail DistributedError,
20
+ 'distributed objects not supported from DeadProtocol'
21
+ end
22
+ end
23
+ end
24
+ end
@@ -0,0 +1,87 @@
1
+
2
+ require 'dizby/protocol/basic'
3
+ require 'dizby/stream/client'
4
+ require 'dizby/stream/connection'
5
+ require 'dizby/server/basic'
6
+ require 'dizby/tunnel/basic'
7
+ require 'dizby/tunnel/factory'
8
+
9
+ require 'socket'
10
+
11
+ module Dizby
12
+ class SecureProtocol
13
+ include BasicProtocol
14
+
15
+ self.scheme = 'drbsec'
16
+
17
+ refine(:spawn,
18
+ "#{scheme}://%{user}?%{host}%{port}?%{query}?"
19
+ ) do |server, command, (user, host, port, query)|
20
+ factory = TunnelFactory.new(server, port)
21
+ tunnel = factory.create(BasicSpawnTunnel).with(command, user, host)
22
+
23
+ socket = TCPSocket.open('localhost', tunnel.local_port)
24
+ TCProtocol.apply_sockopt(socket)
25
+
26
+ delegate = delegatable_tunnel(factory, server, tunnel)
27
+ client = BasicClient.new(delegate, socket,
28
+ "#{scheme}://#{host}:#{tunnel.remote_port}")
29
+ query &&= QueryRef.new(query)
30
+
31
+ [client, query]
32
+ end
33
+
34
+ refine(:client,
35
+ "#{scheme}://%{user}?%{host}%{port}%{query}?"
36
+ ) do |server, (user, host, port, query)|
37
+ port &&= port.to_i
38
+
39
+ factory = TunnelFactory.new(server, port)
40
+ tunnel = factory.create(BasicTunnel).with(user, host)
41
+
42
+ socket = TCPSocket.open('localhost', tunnel.local_port)
43
+ TCProtocol.apply_sockopt(socket)
44
+
45
+ delegate = delegatable_tunnel(factory, server, tunnel)
46
+ client = BasicClient.new(delegate, socket, "#{scheme}://#{host}:#{port}")
47
+ query &&= QueryRef.new(query)
48
+
49
+ [client, query]
50
+ end
51
+
52
+ def self.delegatable_tunnel(factory, server, tunnel)
53
+ if factory.bidirectional?
54
+ ResponseTunnel.new(server, tunnel)
55
+ else
56
+ DirectTunnel.new(server, tunnel)
57
+ end
58
+ end
59
+
60
+ class DirectTunnel < Delegator
61
+ def initialize(server, tunnel)
62
+ super(server)
63
+
64
+ @tunnel = tunnel
65
+ end
66
+
67
+ def close
68
+ @tunnel.close
69
+ super
70
+ @tunnel.thread.join
71
+ end
72
+ end
73
+
74
+ class ResponseTunnel < DirectTunnel
75
+ def initialize(server, tunnel)
76
+ super(server, tunnel)
77
+
78
+ @remote_port = tunnel.remote_port
79
+ end
80
+
81
+ def uri # overload the uri of the server
82
+ # we use the drb protocol for the rebound connection
83
+ "drb://localhost:#{@remote_port}"
84
+ end
85
+ end
86
+ end
87
+ end
@@ -0,0 +1,98 @@
1
+
2
+ require 'dizby/protocol/basic'
3
+ require 'dizby/stream/client'
4
+ require 'dizby/stream/connection'
5
+ require 'dizby/server/basic'
6
+
7
+ require 'socket'
8
+
9
+ module Dizby
10
+ class TCProtocol
11
+ include BasicProtocol
12
+
13
+ self.scheme = 'drb'
14
+
15
+ refine(:server,
16
+ "#{scheme}://%{host}?%{port}?"
17
+ ) do |front, config, (host, port)|
18
+ port &&= port.to_i
19
+
20
+ Server.new front, config, host, port
21
+ end
22
+
23
+ refine(:client,
24
+ "#{scheme}://%{host}?%{port}?%{query}?"
25
+ ) do |server, (host, port, query)|
26
+ port &&= port.to_i
27
+
28
+ socket = TCPSocket.open(host, port)
29
+ apply_sockopt(socket)
30
+
31
+ client = BasicClient.new(server, socket, "#{scheme}://#{host}:#{port}")
32
+ query &&= QueryRef.new(query)
33
+
34
+ [client, query]
35
+ end
36
+
37
+ class << self
38
+ def getservername
39
+ Socket.gethostbyname(Socket.gethostname)[0]
40
+ rescue
41
+ 'localhost'
42
+ end
43
+
44
+ def apply_sockopt(soc)
45
+ soc.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
46
+ end
47
+ end
48
+
49
+ class Server < BasicServer
50
+ include PolymorphicDelegated
51
+
52
+ def initialize(front, config, host, port)
53
+ port ||= 0
54
+
55
+ if host.empty?
56
+ host = TCProtocol.getservername
57
+ socket = self.class.open_socket_inaddr_any(host, port)
58
+ else
59
+ socket = TCPServer.open(host, port)
60
+ end
61
+
62
+ port = socket.addr[1] if port == 0
63
+
64
+ super("drb://#{host}:#{port}", front, socket, config)
65
+
66
+ TCProtocol.apply_sockopt(socket)
67
+
68
+ @port = port
69
+ end
70
+
71
+ attr_reader :port
72
+
73
+ def accept
74
+ socket = nil
75
+ loop do
76
+ socket = super
77
+ break if !tcp_acl || tcp_acl.allow_socket?(socket) # TODO: not tested
78
+ socket.close
79
+ end
80
+
81
+ TCProtocol.apply_sockopt(socket)
82
+ BasicConnection.new(self, socket)
83
+ end
84
+
85
+ config_reader :tcp_acl
86
+ private :tcp_acl
87
+
88
+ def self.open_socket_inaddr_any(host, port)
89
+ infos = Socket.getaddrinfo(host, nil, Socket::AF_UNSPEC,
90
+ Socket::SOCK_STREAM, 0, Socket::AI_PASSIVE)
91
+ families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
92
+ return TCPServer.open('0.0.0.0', port) if families.key?('AF_INET')
93
+ return TCPServer.open('::', port) if families.key?('AF_INET6')
94
+ TCPServer.open(port)
95
+ end
96
+ end
97
+ end
98
+ end
@@ -0,0 +1,95 @@
1
+
2
+ require 'dizby/protocol/basic'
3
+ require 'dizby/stream/client'
4
+ require 'dizby/stream/connection'
5
+ require 'dizby/server/basic'
6
+
7
+ require 'socket'
8
+ require 'tempfile'
9
+
10
+ fail LoadError, 'UNIXServer is required' unless defined?(UNIXServer)
11
+
12
+ module Dizby
13
+ class UnixProtocol
14
+ include BasicProtocol
15
+
16
+ self.scheme = 'drbunix'
17
+
18
+ refine(:server,
19
+ "#{scheme}:%{file}?"
20
+ ) do |front, config, (filename)|
21
+ Server.new front, config, filename
22
+ end
23
+
24
+ refine(:client,
25
+ "#{scheme}:%{file}%{query}?"
26
+ ) do |server, (filename, query)|
27
+ socket = UNIXSocket.open(filename)
28
+ UnixProtocol.apply_sockopt(socket)
29
+
30
+ client = BasicClient.new server, socket, "#{scheme}:#{filename}"
31
+ query &&= QueryRef.new(query)
32
+
33
+ [client, query]
34
+ end
35
+
36
+ def self.apply_sockopt(_soc)
37
+ # no-op for now
38
+ end
39
+
40
+ class Server < BasicServer
41
+ include PolymorphicDelegated
42
+
43
+ def initialize(front, config, filename)
44
+ unless filename
45
+ temp = Tempfile.new(%w( dizby-unix .socket ))
46
+ filename = temp.path
47
+ temp.close!
48
+ end
49
+
50
+ socket = UNIXServer.open(filename)
51
+ UnixProtocol.apply_sockopt(socket)
52
+
53
+ super("drbunix:#{filename}", front, socket, config)
54
+
55
+ self.class.set_permissions(filename, config)
56
+ end
57
+
58
+ def close
59
+ if stream
60
+ path = stream.path
61
+ stream.close
62
+ self.stream = nil
63
+
64
+ log.debug("unlinking #{path}")
65
+ File.unlink(path)
66
+ end
67
+
68
+ close_shutdown_pipe
69
+ end
70
+
71
+ def accept
72
+ socket = super
73
+
74
+ UnixProtocol.apply_sockopt(socket)
75
+ BasicConnection.new(self, socket)
76
+ end
77
+
78
+ def self.set_permissions(filename, config)
79
+ owner = config[:unix_owner]
80
+ group = config[:unix_group]
81
+ mode = config[:unix_mode]
82
+
83
+ if owner || group
84
+ require 'etc'
85
+ owner = Etc.getpwnam(owner).uid if owner
86
+ group = Etc.getgrnam(group).gid if group
87
+ File.chown(owner, group, filename)
88
+ end
89
+
90
+ File.chmod(mode, filename) if mode
91
+ end
92
+ private_class_method :set_permissions
93
+ end
94
+ end
95
+ end