drab 0.1.0
Sign up to get free protection for your applications and to get access to all the features.
- checksums.yaml +7 -0
- data/.gitignore +3 -0
- data/Gemfile +8 -0
- data/Gemfile.lock.bak +38 -0
- data/LICENSE +59 -0
- data/README.md +2 -0
- data/Rakefile +6 -0
- data/bin/console +14 -0
- data/bin/setup +8 -0
- data/drab.gemspec +40 -0
- data/lib/drab.rb +2 -0
- data/lib/drab/acl.rb +232 -0
- data/lib/drab/drab.rb +1499 -0
- data/lib/drab/eq.rb +15 -0
- data/lib/drab/extserv.rb +44 -0
- data/lib/drab/extservm.rb +94 -0
- data/lib/drab/gw.rb +165 -0
- data/lib/drab/invokemethod.rb +35 -0
- data/lib/drab/observer.rb +26 -0
- data/lib/drab/ssl.rb +346 -0
- data/lib/drab/timeridconv.rb +97 -0
- data/lib/drab/unix.rb +118 -0
- data/lib/drab/version.rb +3 -0
- metadata +124 -0
checksums.yaml
ADDED
@@ -0,0 +1,7 @@
|
|
1
|
+
---
|
2
|
+
SHA1:
|
3
|
+
metadata.gz: 5481db4287eb6cb52247f7168320c885184a05d6
|
4
|
+
data.tar.gz: 62553e86a2b6f0dbfeb3bc313d189f26fb31d393
|
5
|
+
SHA512:
|
6
|
+
metadata.gz: f981513e4fa4ce1afc0c2f1cd61a2abaffbbb0a7b51b336615c9fd160a28518dde8ca9528f02210ecb39f3e9a339227ad1a33c9dbb9f36d19b05afb1bf674200
|
7
|
+
data.tar.gz: 65854246a51b043cb837978eda03babcdb53882013a1d845795988c5e664342cbf665bd48236ab27c8fe11f0de90531f825ab1c5dc5f3142e58183221c68e0ef
|
data/.gitignore
ADDED
data/Gemfile
ADDED
data/Gemfile.lock.bak
ADDED
@@ -0,0 +1,38 @@
|
|
1
|
+
PATH
|
2
|
+
remote: .
|
3
|
+
specs:
|
4
|
+
drab (0.1.0)
|
5
|
+
marshal-structure (~> 2.0)
|
6
|
+
|
7
|
+
GEM
|
8
|
+
remote: https://rubygems.org/
|
9
|
+
specs:
|
10
|
+
diff-lcs (1.3)
|
11
|
+
marshal-structure (2.0)
|
12
|
+
rake (10.5.0)
|
13
|
+
rspec (3.6.0)
|
14
|
+
rspec-core (~> 3.6.0)
|
15
|
+
rspec-expectations (~> 3.6.0)
|
16
|
+
rspec-mocks (~> 3.6.0)
|
17
|
+
rspec-core (3.6.0)
|
18
|
+
rspec-support (~> 3.6.0)
|
19
|
+
rspec-expectations (3.6.0)
|
20
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
21
|
+
rspec-support (~> 3.6.0)
|
22
|
+
rspec-mocks (3.6.0)
|
23
|
+
diff-lcs (>= 1.2.0, < 2.0)
|
24
|
+
rspec-support (~> 3.6.0)
|
25
|
+
rspec-support (3.6.0)
|
26
|
+
|
27
|
+
PLATFORMS
|
28
|
+
ruby
|
29
|
+
|
30
|
+
DEPENDENCIES
|
31
|
+
bundler (~> 1.13)
|
32
|
+
drab!
|
33
|
+
rake (~> 10.0)
|
34
|
+
rb-readline
|
35
|
+
rspec (~> 3.0)
|
36
|
+
|
37
|
+
BUNDLED WITH
|
38
|
+
1.15.4
|
data/LICENSE
ADDED
@@ -0,0 +1,59 @@
|
|
1
|
+
secure_compare in lib/drab/drab.rb is sourced from rails/rails and licensed
|
2
|
+
under the MIT license.
|
3
|
+
|
4
|
+
Ruby is copyrighted free software by Yukihiro Matsumoto <matz@netlab.jp>.
|
5
|
+
You can redistribute it and/or modify it under either the terms of the
|
6
|
+
2-clause BSDL (see the file BSDL), or the conditions below:
|
7
|
+
|
8
|
+
1. You may make and give away verbatim copies of the source form of the
|
9
|
+
software without restriction, provided that you duplicate all of the
|
10
|
+
original copyright notices and associated disclaimers.
|
11
|
+
|
12
|
+
2. You may modify your copy of the software in any way, provided that
|
13
|
+
you do at least ONE of the following:
|
14
|
+
|
15
|
+
a) place your modifications in the Public Domain or otherwise
|
16
|
+
make them Freely Available, such as by posting said
|
17
|
+
modifications to Usenet or an equivalent medium, or by allowing
|
18
|
+
the author to include your modifications in the software.
|
19
|
+
|
20
|
+
b) use the modified software only within your corporation or
|
21
|
+
organization.
|
22
|
+
|
23
|
+
c) give non-standard binaries non-standard names, with
|
24
|
+
instructions on where to get the original software distribution.
|
25
|
+
|
26
|
+
d) make other distribution arrangements with the author.
|
27
|
+
|
28
|
+
3. You may distribute the software in object code or binary form,
|
29
|
+
provided that you do at least ONE of the following:
|
30
|
+
|
31
|
+
a) distribute the binaries and library files of the software,
|
32
|
+
together with instructions (in the manual page or equivalent)
|
33
|
+
on where to get the original distribution.
|
34
|
+
|
35
|
+
b) accompany the distribution with the machine-readable source of
|
36
|
+
the software.
|
37
|
+
|
38
|
+
c) give non-standard binaries non-standard names, with
|
39
|
+
instructions on where to get the original software distribution.
|
40
|
+
|
41
|
+
d) make other distribution arrangements with the author.
|
42
|
+
|
43
|
+
4. You may modify and include the part of the software into any other
|
44
|
+
software (possibly commercial). But some files in the distribution
|
45
|
+
are not written by the author, so that they are not under these terms.
|
46
|
+
|
47
|
+
For the list of those files and their copying conditions, see the
|
48
|
+
file LEGAL.
|
49
|
+
|
50
|
+
5. The scripts and library files supplied as input to or produced as
|
51
|
+
output from the software do not automatically fall under the
|
52
|
+
copyright of the software, but belong to whomever generated them,
|
53
|
+
and may be sold commercially, and may be aggregated with this
|
54
|
+
software.
|
55
|
+
|
56
|
+
6. THIS SOFTWARE IS PROVIDED "AS IS" AND WITHOUT ANY EXPRESS OR
|
57
|
+
IMPLIED WARRANTIES, INCLUDING, WITHOUT LIMITATION, THE IMPLIED
|
58
|
+
WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR
|
59
|
+
PURPOSE.
|
data/README.md
ADDED
data/Rakefile
ADDED
data/bin/console
ADDED
@@ -0,0 +1,14 @@
|
|
1
|
+
#!/usr/bin/env ruby
|
2
|
+
|
3
|
+
require "bundler/setup"
|
4
|
+
require "drab"
|
5
|
+
|
6
|
+
# You can add fixtures and/or initialization code here to make experimenting
|
7
|
+
# with your gem easier. You can also use a different console, if you like.
|
8
|
+
|
9
|
+
# (If you use this, don't forget to add pry to your Gemfile!)
|
10
|
+
# require "pry"
|
11
|
+
# Pry.start
|
12
|
+
|
13
|
+
require "irb"
|
14
|
+
IRB.start
|
data/bin/setup
ADDED
data/drab.gemspec
ADDED
@@ -0,0 +1,40 @@
|
|
1
|
+
# coding: utf-8
|
2
|
+
lib = File.expand_path('../lib', __FILE__)
|
3
|
+
$LOAD_PATH.unshift(lib) unless $LOAD_PATH.include?(lib)
|
4
|
+
require 'drab/version'
|
5
|
+
|
6
|
+
Gem::Specification.new do |spec|
|
7
|
+
spec.name = "drab"
|
8
|
+
spec.version = DRab::VERSION
|
9
|
+
spec.authors = ["Masatoshi SEKI", "Jeff Dileo"]
|
10
|
+
spec.email = ["jtdileo@gmail.com"]
|
11
|
+
spec.summary = "Make DRb great again!"
|
12
|
+
spec.description = spec.summary
|
13
|
+
spec.homepage = "https://github.com/chaosdata/drab"
|
14
|
+
spec.licenses = ['Ruby']
|
15
|
+
|
16
|
+
spec.required_ruby_version = '>= 1.9.3'
|
17
|
+
|
18
|
+
# Prevent pushing this gem to RubyGems.org. To allow pushes either set the 'allowed_push_host'
|
19
|
+
# to allow pushing to a single host or delete this section to allow pushing to any host.
|
20
|
+
if spec.respond_to?(:metadata)
|
21
|
+
spec.metadata['allowed_push_host'] = "https://rubygems.org"
|
22
|
+
else
|
23
|
+
raise "RubyGems 2.0 or newer is required to protect against " \
|
24
|
+
"public gem pushes."
|
25
|
+
end
|
26
|
+
|
27
|
+
#spec.files = `git ls-files lib *.md LICENSE`.split("\n")
|
28
|
+
spec.files = `git ls-files -z`.split("\x0").reject do |f|
|
29
|
+
f.match(%r{^(test|spec|features)/})
|
30
|
+
end
|
31
|
+
spec.bindir = "exe"
|
32
|
+
spec.executables = spec.files.grep(%r{^exe/}) { |f| File.basename(f) }
|
33
|
+
spec.require_paths = ["lib"]
|
34
|
+
|
35
|
+
spec.add_dependency "marshal-structure", "~> 2.0"
|
36
|
+
|
37
|
+
spec.add_development_dependency "bundler", "~> 1.13"
|
38
|
+
spec.add_development_dependency "rake", "~> 10.0"
|
39
|
+
spec.add_development_dependency "rspec", "~> 3.0"
|
40
|
+
end
|
data/lib/drab.rb
ADDED
data/lib/drab/acl.rb
ADDED
@@ -0,0 +1,232 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
# Copyright (c) 2000,2002,2003 Masatoshi SEKI
|
3
|
+
#
|
4
|
+
# acl.rb is copyrighted free software by Masatoshi SEKI.
|
5
|
+
# You can redistribute it and/or modify it under the same terms as Ruby.
|
6
|
+
|
7
|
+
require 'ipaddr'
|
8
|
+
|
9
|
+
##
|
10
|
+
# Simple Access Control Lists.
|
11
|
+
#
|
12
|
+
# Access control lists are composed of "allow" and "deny" halves to control
|
13
|
+
# access. Use "all" or "*" to match any address. To match a specific address
|
14
|
+
# use any address or address mask that IPAddr can understand.
|
15
|
+
#
|
16
|
+
# Example:
|
17
|
+
#
|
18
|
+
# list = %w[
|
19
|
+
# deny all
|
20
|
+
# allow 192.168.1.1
|
21
|
+
# allow ::ffff:192.168.1.2
|
22
|
+
# allow 192.168.1.3
|
23
|
+
# ]
|
24
|
+
#
|
25
|
+
# # From Socket#peeraddr, see also ACL#allow_socket?
|
26
|
+
# addr = ["AF_INET", 10, "lc630", "192.168.1.3"]
|
27
|
+
#
|
28
|
+
# acl = ACL.new
|
29
|
+
# p acl.allow_addr?(addr) # => true
|
30
|
+
#
|
31
|
+
# acl = ACL.new(list, ACL::DENY_ALLOW)
|
32
|
+
# p acl.allow_addr?(addr) # => true
|
33
|
+
|
34
|
+
class ACL
|
35
|
+
|
36
|
+
##
|
37
|
+
# The current version of ACL
|
38
|
+
|
39
|
+
VERSION=["2.0.0"]
|
40
|
+
|
41
|
+
##
|
42
|
+
# An entry in an ACL
|
43
|
+
|
44
|
+
class ACLEntry
|
45
|
+
|
46
|
+
##
|
47
|
+
# Creates a new entry using +str+.
|
48
|
+
#
|
49
|
+
# +str+ may be "*" or "all" to match any address, an IP address string
|
50
|
+
# to match a specific address, an IP address mask per IPAddr, or one
|
51
|
+
# containing "*" to match part of an IPv4 address.
|
52
|
+
|
53
|
+
def initialize(str)
|
54
|
+
if str == '*' or str == 'all'
|
55
|
+
@pat = [:all]
|
56
|
+
elsif str.include?('*')
|
57
|
+
@pat = [:name, dot_pat(str)]
|
58
|
+
else
|
59
|
+
begin
|
60
|
+
@pat = [:ip, IPAddr.new(str)]
|
61
|
+
rescue ArgumentError
|
62
|
+
@pat = [:name, dot_pat(str)]
|
63
|
+
end
|
64
|
+
end
|
65
|
+
end
|
66
|
+
|
67
|
+
private
|
68
|
+
|
69
|
+
##
|
70
|
+
# Creates a regular expression to match IPv4 addresses
|
71
|
+
|
72
|
+
def dot_pat_str(str)
|
73
|
+
list = str.split('.').collect { |s|
|
74
|
+
(s == '*') ? '.+' : s
|
75
|
+
}
|
76
|
+
list.join("\\.")
|
77
|
+
end
|
78
|
+
|
79
|
+
private
|
80
|
+
|
81
|
+
##
|
82
|
+
# Creates a Regexp to match an address.
|
83
|
+
|
84
|
+
def dot_pat(str)
|
85
|
+
/\A#{dot_pat_str(str)}\z/
|
86
|
+
end
|
87
|
+
|
88
|
+
public
|
89
|
+
|
90
|
+
##
|
91
|
+
# Matches +addr+ against this entry.
|
92
|
+
|
93
|
+
def match(addr)
|
94
|
+
case @pat[0]
|
95
|
+
when :all
|
96
|
+
true
|
97
|
+
when :ip
|
98
|
+
begin
|
99
|
+
ipaddr = IPAddr.new(addr[3])
|
100
|
+
ipaddr = ipaddr.ipv4_mapped if @pat[1].ipv6? && ipaddr.ipv4?
|
101
|
+
rescue ArgumentError
|
102
|
+
return false
|
103
|
+
end
|
104
|
+
(@pat[1].include?(ipaddr)) ? true : false
|
105
|
+
when :name
|
106
|
+
(@pat[1] =~ addr[2]) ? true : false
|
107
|
+
else
|
108
|
+
false
|
109
|
+
end
|
110
|
+
end
|
111
|
+
end
|
112
|
+
|
113
|
+
##
|
114
|
+
# A list of ACLEntry objects. Used to implement the allow and deny halves
|
115
|
+
# of an ACL
|
116
|
+
|
117
|
+
class ACLList
|
118
|
+
|
119
|
+
##
|
120
|
+
# Creates an empty ACLList
|
121
|
+
|
122
|
+
def initialize
|
123
|
+
@list = []
|
124
|
+
end
|
125
|
+
|
126
|
+
public
|
127
|
+
|
128
|
+
##
|
129
|
+
# Matches +addr+ against each ACLEntry in this list.
|
130
|
+
|
131
|
+
def match(addr)
|
132
|
+
@list.each do |e|
|
133
|
+
return true if e.match(addr)
|
134
|
+
end
|
135
|
+
false
|
136
|
+
end
|
137
|
+
|
138
|
+
public
|
139
|
+
|
140
|
+
##
|
141
|
+
# Adds +str+ as an ACLEntry in this list
|
142
|
+
|
143
|
+
def add(str)
|
144
|
+
@list.push(ACLEntry.new(str))
|
145
|
+
end
|
146
|
+
|
147
|
+
end
|
148
|
+
|
149
|
+
##
|
150
|
+
# Default to deny
|
151
|
+
|
152
|
+
DENY_ALLOW = 0
|
153
|
+
|
154
|
+
##
|
155
|
+
# Default to allow
|
156
|
+
|
157
|
+
ALLOW_DENY = 1
|
158
|
+
|
159
|
+
##
|
160
|
+
# Creates a new ACL from +list+ with an evaluation +order+ of DENY_ALLOW or
|
161
|
+
# ALLOW_DENY.
|
162
|
+
#
|
163
|
+
# An ACL +list+ is an Array of "allow" or "deny" and an address or address
|
164
|
+
# mask or "all" or "*" to match any address:
|
165
|
+
#
|
166
|
+
# %w[
|
167
|
+
# deny all
|
168
|
+
# allow 192.0.2.2
|
169
|
+
# allow 192.0.2.128/26
|
170
|
+
# ]
|
171
|
+
|
172
|
+
def initialize(list=nil, order = DENY_ALLOW)
|
173
|
+
@order = order
|
174
|
+
@deny = ACLList.new
|
175
|
+
@allow = ACLList.new
|
176
|
+
install_list(list) if list
|
177
|
+
end
|
178
|
+
|
179
|
+
public
|
180
|
+
|
181
|
+
##
|
182
|
+
# Allow connections from Socket +soc+?
|
183
|
+
|
184
|
+
def allow_socket?(soc)
|
185
|
+
allow_addr?(soc.peeraddr)
|
186
|
+
end
|
187
|
+
|
188
|
+
public
|
189
|
+
|
190
|
+
##
|
191
|
+
# Allow connections from addrinfo +addr+? It must be formatted like
|
192
|
+
# Socket#peeraddr:
|
193
|
+
#
|
194
|
+
# ["AF_INET", 10, "lc630", "192.0.2.1"]
|
195
|
+
|
196
|
+
def allow_addr?(addr)
|
197
|
+
case @order
|
198
|
+
when DENY_ALLOW
|
199
|
+
return true if @allow.match(addr)
|
200
|
+
return false if @deny.match(addr)
|
201
|
+
return true
|
202
|
+
when ALLOW_DENY
|
203
|
+
return false if @deny.match(addr)
|
204
|
+
return true if @allow.match(addr)
|
205
|
+
return false
|
206
|
+
else
|
207
|
+
false
|
208
|
+
end
|
209
|
+
end
|
210
|
+
|
211
|
+
public
|
212
|
+
|
213
|
+
##
|
214
|
+
# Adds +list+ of ACL entries to this ACL.
|
215
|
+
|
216
|
+
def install_list(list)
|
217
|
+
i = 0
|
218
|
+
while i < list.size
|
219
|
+
permission, domain = list.slice(i,2)
|
220
|
+
case permission.downcase
|
221
|
+
when 'allow'
|
222
|
+
@allow.add(domain)
|
223
|
+
when 'deny'
|
224
|
+
@deny.add(domain)
|
225
|
+
else
|
226
|
+
raise "Invalid ACL entry #{list}"
|
227
|
+
end
|
228
|
+
i += 2
|
229
|
+
end
|
230
|
+
end
|
231
|
+
|
232
|
+
end
|
data/lib/drab/drab.rb
ADDED
@@ -0,0 +1,1499 @@
|
|
1
|
+
# frozen_string_literal: false
|
2
|
+
#
|
3
|
+
# = ./drab.rb
|
4
|
+
#
|
5
|
+
# Restricted Distributed Ruby: _drab_ version 0.1.0
|
6
|
+
#
|
7
|
+
# Copyright (c) 1999-2003 Masatoshi SEKI. You can redistribute it and/or
|
8
|
+
# modify it under the same terms as Ruby.
|
9
|
+
#
|
10
|
+
# Author:: Masatoshi SEKI, Jeff Dileo
|
11
|
+
#
|
12
|
+
|
13
|
+
require 'socket'
|
14
|
+
require 'thread'
|
15
|
+
require 'io/wait'
|
16
|
+
require 'drab/eq'
|
17
|
+
require 'json'
|
18
|
+
require 'marshal/structure'
|
19
|
+
require 'set'
|
20
|
+
|
21
|
+
module DRab
|
22
|
+
|
23
|
+
class DRabError < RuntimeError; end
|
24
|
+
class DRabConnError < DRabError; end
|
25
|
+
|
26
|
+
class DRabIdConv
|
27
|
+
@@ids = {} # totally a memory leak, but not much that can be done
|
28
|
+
# unless there's a way to remove recycled objects' ids
|
29
|
+
|
30
|
+
|
31
|
+
def to_obj(ref)
|
32
|
+
if @@ids.include?(ref)
|
33
|
+
#ObjectSpace._id2ref(ref)
|
34
|
+
@@ids[ref]
|
35
|
+
else
|
36
|
+
STDERR.puts "attempted to load an unshared object by object id"
|
37
|
+
raise Exception.new("attempted to load an unshared object by object id")
|
38
|
+
end
|
39
|
+
end
|
40
|
+
|
41
|
+
def to_id(obj)
|
42
|
+
ret = obj.nil? ? nil : obj.__id__
|
43
|
+
#@@id_list.add(ret)
|
44
|
+
@@ids[ret] = obj
|
45
|
+
ret
|
46
|
+
end
|
47
|
+
end
|
48
|
+
|
49
|
+
module DRabUndumped
|
50
|
+
def _dump(dummy)
|
51
|
+
raise TypeError, "can't/won't dump"
|
52
|
+
end
|
53
|
+
end
|
54
|
+
|
55
|
+
class DRabServerNotFound < DRabError; end
|
56
|
+
class DRabBadURI < DRabError; end
|
57
|
+
class DRabBadScheme < DRabError; end
|
58
|
+
|
59
|
+
class DRabUnknownError < DRabError
|
60
|
+
|
61
|
+
def initialize(unknown)
|
62
|
+
@unknown = unknown
|
63
|
+
super(unknown.name)
|
64
|
+
end
|
65
|
+
|
66
|
+
attr_reader :unknown
|
67
|
+
|
68
|
+
#def self._load(s) # :nodoc:
|
69
|
+
# Marshal::load(s)
|
70
|
+
#end
|
71
|
+
|
72
|
+
#def _dump(lv) # :nodoc:
|
73
|
+
# Marshal::dump(@unknown)
|
74
|
+
#end
|
75
|
+
end
|
76
|
+
|
77
|
+
class DRabRemoteError < DRabError
|
78
|
+
|
79
|
+
def initialize(error)
|
80
|
+
@reason = error.class.to_s
|
81
|
+
super("#{error.message} (#{error.class})")
|
82
|
+
set_backtrace(error.backtrace)
|
83
|
+
end
|
84
|
+
|
85
|
+
attr_reader :reason
|
86
|
+
end
|
87
|
+
|
88
|
+
class DRabUnknown
|
89
|
+
|
90
|
+
def initialize(err, buf)
|
91
|
+
case err.to_s
|
92
|
+
when /uninitialized constant (\S+)/
|
93
|
+
@name = $1
|
94
|
+
when /undefined class\/module (\S+)/
|
95
|
+
@name = $1
|
96
|
+
else
|
97
|
+
@name = nil
|
98
|
+
end
|
99
|
+
@buf = buf
|
100
|
+
end
|
101
|
+
|
102
|
+
attr_reader :name
|
103
|
+
|
104
|
+
attr_reader :buf
|
105
|
+
|
106
|
+
#def self._load(s) # :nodoc:
|
107
|
+
# begin
|
108
|
+
# Marshal::load(s)
|
109
|
+
# rescue NameError, ArgumentError
|
110
|
+
# DRabUnknown.new($!, s)
|
111
|
+
# end
|
112
|
+
#end
|
113
|
+
|
114
|
+
#def _dump(lv) # :nodoc:
|
115
|
+
# @buf
|
116
|
+
#end
|
117
|
+
|
118
|
+
#def reload
|
119
|
+
# self.class._load(@buf)
|
120
|
+
#end
|
121
|
+
|
122
|
+
def exception
|
123
|
+
DRabUnknownError.new(self)
|
124
|
+
end
|
125
|
+
end
|
126
|
+
|
127
|
+
class DRabArray
|
128
|
+
class Token
|
129
|
+
def initialize(sz)
|
130
|
+
@size = sz
|
131
|
+
end
|
132
|
+
|
133
|
+
def size
|
134
|
+
@size
|
135
|
+
end
|
136
|
+
|
137
|
+
def self._load(s)
|
138
|
+
sz = JSON::load(s)
|
139
|
+
if sz.is_a?(Integer)
|
140
|
+
self.new(sz)
|
141
|
+
else
|
142
|
+
raise Exception.new("got non-integer JSON when parsing DRabArray")
|
143
|
+
end
|
144
|
+
end
|
145
|
+
|
146
|
+
def _dump(lv)
|
147
|
+
JSON::dump(@size)
|
148
|
+
end
|
149
|
+
end
|
150
|
+
|
151
|
+
def initialize(ary)
|
152
|
+
@ary = ary.collect { |obj|
|
153
|
+
if obj.kind_of? DRabUndumped
|
154
|
+
DRabObject.new(obj)
|
155
|
+
else
|
156
|
+
begin
|
157
|
+
obj
|
158
|
+
rescue
|
159
|
+
DRabObject.new(obj)
|
160
|
+
end
|
161
|
+
end
|
162
|
+
}
|
163
|
+
end
|
164
|
+
|
165
|
+
def get
|
166
|
+
@ary
|
167
|
+
end
|
168
|
+
|
169
|
+
def self._load(s)
|
170
|
+
raise Exception.new("not marshallable")
|
171
|
+
end
|
172
|
+
|
173
|
+
def self._dump(lv)
|
174
|
+
raise Exception.new("not marshallable")
|
175
|
+
end
|
176
|
+
end
|
177
|
+
|
178
|
+
|
179
|
+
class DRabMessage
|
180
|
+
def initialize(config)
|
181
|
+
@load_limit = config[:load_limit]
|
182
|
+
@argc_limit = config[:argc_limit]
|
183
|
+
end
|
184
|
+
|
185
|
+
def dump(obj, error=false, as_json = false)
|
186
|
+
if as_json
|
187
|
+
str = JSON::dump(obj)
|
188
|
+
return [str.size].pack('N') + str
|
189
|
+
end
|
190
|
+
|
191
|
+
if obj.is_a?(DRabUndumped)
|
192
|
+
obj = make_proxy(obj, error)
|
193
|
+
elsif obj.is_a?(Proc)
|
194
|
+
obj = make_proxy(obj, error)
|
195
|
+
elsif obj.is_a?(DRabArray)
|
196
|
+
p = dump(DRabArray::Token.new(obj.get.size), error)
|
197
|
+
obj.get.each { |o| p += dump(o) }
|
198
|
+
return p
|
199
|
+
end
|
200
|
+
|
201
|
+
begin
|
202
|
+
str = Marshal::dump(obj)
|
203
|
+
rescue
|
204
|
+
#str = Marshal::dump(make_proxy(obj, error))
|
205
|
+
STDERR.puts "failed to marshal value of type " + obj.class.to_s + ", not exposing a proxy"
|
206
|
+
str = Marshal::dump(nil)
|
207
|
+
end
|
208
|
+
[str.size].pack('N') + str
|
209
|
+
end
|
210
|
+
|
211
|
+
def load(soc, as_json = false)
|
212
|
+
begin
|
213
|
+
sz = soc.read(4)
|
214
|
+
rescue
|
215
|
+
raise(DRabConnError, $!.message, $!.backtrace)
|
216
|
+
end
|
217
|
+
raise(DRabConnError, 'connection closed') if sz.nil?
|
218
|
+
raise(DRabConnError, 'premature header') if sz.size < 4
|
219
|
+
sz = sz.unpack('N')[0]
|
220
|
+
raise(DRabConnError, "too large packet #{sz}") if @load_limit < sz
|
221
|
+
begin
|
222
|
+
str = soc.read(sz)
|
223
|
+
rescue
|
224
|
+
raise(DRabConnError, $!.message, $!.backtrace)
|
225
|
+
end
|
226
|
+
raise(DRabConnError, 'connection closed') if str.nil?
|
227
|
+
raise(DRabConnError, 'premature marshal format(can\'t read)') if str.size < sz
|
228
|
+
|
229
|
+
if not as_json
|
230
|
+
begin
|
231
|
+
typ, structure = parse_marshal(str)
|
232
|
+
rescue Exception => e
|
233
|
+
end
|
234
|
+
end
|
235
|
+
|
236
|
+
DRab.mutex.synchronize do
|
237
|
+
begin
|
238
|
+
save = Thread.current[:drab_untaint]
|
239
|
+
Thread.current[:drab_untaint] = []
|
240
|
+
if as_json
|
241
|
+
JSON::load(str)
|
242
|
+
else
|
243
|
+
if typ.between?(Types::Bln, Types::Arr)
|
244
|
+
Marshal::load(str)
|
245
|
+
elsif typ === Types::Err
|
246
|
+
Exception.new(s.to_s)
|
247
|
+
else
|
248
|
+
STDERR.puts "got weird object: " + str.inspect + "\nwith structure: " + structure.inspect
|
249
|
+
nil
|
250
|
+
end
|
251
|
+
end
|
252
|
+
rescue NameError, ArgumentError => e
|
253
|
+
puts e
|
254
|
+
puts e.backtrace
|
255
|
+
DRabUnknown.new($!, str)
|
256
|
+
ensure
|
257
|
+
Thread.current[:drab_untaint].each do |x|
|
258
|
+
x.untaint
|
259
|
+
end
|
260
|
+
Thread.current[:drab_untaint] = save
|
261
|
+
end
|
262
|
+
end
|
263
|
+
end
|
264
|
+
|
265
|
+
def send_request(stream, ref, msg_id, arg, b)
|
266
|
+
ary = []
|
267
|
+
ary.push(dump(ref.__drabref, false, true))
|
268
|
+
ary.push(dump(msg_id.id2name, false, true))
|
269
|
+
ary.push(dump(arg.length, false, true))
|
270
|
+
arg.each do |e|
|
271
|
+
ary.push(dump(e))
|
272
|
+
end
|
273
|
+
#ary.push(dump(b))
|
274
|
+
|
275
|
+
send_secret(stream)
|
276
|
+
stream.write(ary.join(''))
|
277
|
+
rescue
|
278
|
+
raise(DRabConnError, $!.message, $!.backtrace)
|
279
|
+
end
|
280
|
+
|
281
|
+
def match_structures(template, target)
|
282
|
+
begin
|
283
|
+
if not (template.is_a?(Array) and target.is_a?(Array))
|
284
|
+
return false
|
285
|
+
end
|
286
|
+
|
287
|
+
if template.size != target.size
|
288
|
+
return false
|
289
|
+
end
|
290
|
+
|
291
|
+
template.size.times do |n|
|
292
|
+
if template[n].is_a?(Array)
|
293
|
+
return match_structures(template[n], target[n])
|
294
|
+
end
|
295
|
+
|
296
|
+
if template[n] === target[n]
|
297
|
+
return true
|
298
|
+
end
|
299
|
+
|
300
|
+
if template[n].is_a?(String) and target[n].is_a?(String)
|
301
|
+
if template[n] === "*"
|
302
|
+
return true
|
303
|
+
elsif template[n].start_with?("*")
|
304
|
+
return target[n].end_with?(template[n][1..-1])
|
305
|
+
elsif template[n].end_with?("*")
|
306
|
+
return target[n].start_with?(template[n][0..-2])
|
307
|
+
end
|
308
|
+
end
|
309
|
+
end
|
310
|
+
rescue Exception => e
|
311
|
+
STDERR.puts e
|
312
|
+
STDERR.puts e.backtrace
|
313
|
+
end
|
314
|
+
return false
|
315
|
+
end
|
316
|
+
|
317
|
+
module Types
|
318
|
+
Ukn = 0
|
319
|
+
Bln = 1
|
320
|
+
Nil = 2
|
321
|
+
Sym = 3
|
322
|
+
Num = 4
|
323
|
+
DRb = 5
|
324
|
+
Str = 6
|
325
|
+
Arr = 7
|
326
|
+
Err = 8
|
327
|
+
end
|
328
|
+
|
329
|
+
|
330
|
+
def parse_marshal(str)
|
331
|
+
begin
|
332
|
+
# i don't know why, but if this runs in the current thread,
|
333
|
+
# the __recursive_key__ state in PP, as invoked by pry, gets mangled
|
334
|
+
msthread = Thread.new { Thread.current[:structure] = Marshal::Structure::load(str) }
|
335
|
+
msthread.join
|
336
|
+
parsed_str = msthread[:structure]
|
337
|
+
if parsed_str === :true or parsed_str === :false
|
338
|
+
return Types::Bln
|
339
|
+
elsif parsed_str === :nil
|
340
|
+
return Types::Nil
|
341
|
+
elsif parsed_str === [:symbol, 0, "write"] # :write
|
342
|
+
return Types::Sym
|
343
|
+
elsif parsed_str === [:symbol, 0, "readline"] # :readline
|
344
|
+
return Types::Sym
|
345
|
+
elsif parsed_str.size === 2 and parsed_str[0] === :fixnum and parsed_str[1].is_a?(Integer)
|
346
|
+
return Types::Num
|
347
|
+
elsif match_structures([ # json DRab::DRabObject
|
348
|
+
:user_defined,
|
349
|
+
0,
|
350
|
+
[:symbol, 0, "DRab::DRabObject"],
|
351
|
+
"*"
|
352
|
+
], parsed_str)
|
353
|
+
return [Types::DRb, parsed_str]
|
354
|
+
elsif match_structures([ # json DRab::DRabObject
|
355
|
+
:instance_variables,
|
356
|
+
[
|
357
|
+
:user_defined,
|
358
|
+
0,
|
359
|
+
[:symbol, 0, "DRab::DRabObject"],
|
360
|
+
"*"
|
361
|
+
],
|
362
|
+
1,
|
363
|
+
[:symbol, 1, "E"],
|
364
|
+
:true
|
365
|
+
], parsed_str)
|
366
|
+
return [Types::DRb, parsed_str]
|
367
|
+
elsif match_structures([ # string
|
368
|
+
:string,
|
369
|
+
0,
|
370
|
+
"*"
|
371
|
+
], parsed_str)
|
372
|
+
return Types::Str
|
373
|
+
elsif match_structures([ # string
|
374
|
+
:instance_variables,
|
375
|
+
[:string, 0, "*"],
|
376
|
+
1,
|
377
|
+
[:symbol, 0, "E"],
|
378
|
+
:false
|
379
|
+
], parsed_str)
|
380
|
+
return Types::Str
|
381
|
+
elsif match_structures([ # json DRab::DRabArray::Token
|
382
|
+
:instance_variables,
|
383
|
+
[
|
384
|
+
:user_defined,
|
385
|
+
0,
|
386
|
+
[:symbol, 0, "DRab::DRabArray::Token"],
|
387
|
+
"*"
|
388
|
+
],
|
389
|
+
1,
|
390
|
+
[:symbol, 1, "E"],
|
391
|
+
:true
|
392
|
+
], parsed_str)
|
393
|
+
return [Types::Arr, parsed_str]
|
394
|
+
elsif match_structures([
|
395
|
+
[:object, 0, [:symbol, 0, "*Error"]]
|
396
|
+
], parsed_str[0..2])
|
397
|
+
return [Types::Err, parsed_str]
|
398
|
+
else
|
399
|
+
return [Types::Ukn, parsed_str]
|
400
|
+
end
|
401
|
+
rescue Exception => e
|
402
|
+
STDERR.puts e
|
403
|
+
STDERR.puts e.backtrace
|
404
|
+
end
|
405
|
+
return [Types::Ukn, parsed_str]
|
406
|
+
end
|
407
|
+
|
408
|
+
BLACKLISTED_BASIC_OBJECT_METHODS = Set.new([
|
409
|
+
"send",
|
410
|
+
"__send__",
|
411
|
+
"method",
|
412
|
+
"methods",
|
413
|
+
"inspect",
|
414
|
+
"private_methods",
|
415
|
+
"protected_methods",
|
416
|
+
"public_method",
|
417
|
+
"public_methods",
|
418
|
+
"public_send",
|
419
|
+
"singleton_class",
|
420
|
+
"singleton_method",
|
421
|
+
"singleton_methods",
|
422
|
+
"taint",
|
423
|
+
"trust",
|
424
|
+
"untaint",
|
425
|
+
"untrust",
|
426
|
+
"instance_eval",
|
427
|
+
"instance_exec",
|
428
|
+
"method_missing",
|
429
|
+
"singleton_method_added",
|
430
|
+
"singleton_method_removed",
|
431
|
+
"instance_variables",
|
432
|
+
"instance_variable_get",
|
433
|
+
"instance_variable_set",
|
434
|
+
"instance_variable_defined?",
|
435
|
+
"remove_instance_variable",
|
436
|
+
])
|
437
|
+
|
438
|
+
BLACKLISTED_MODULE_METHODS = Set.new([
|
439
|
+
"used_modules",
|
440
|
+
"alias_method",
|
441
|
+
"append_features",
|
442
|
+
"attr",
|
443
|
+
"attr_reader",
|
444
|
+
"attr_accessor",
|
445
|
+
"attr_writer",
|
446
|
+
"define_method",
|
447
|
+
"extend_object",
|
448
|
+
"extended",
|
449
|
+
"include",
|
450
|
+
"included",
|
451
|
+
"included_modules",
|
452
|
+
"instance_method",
|
453
|
+
"instance_methods",
|
454
|
+
"module_eval",
|
455
|
+
"module_exec",
|
456
|
+
"prepend",
|
457
|
+
"private_class_method",
|
458
|
+
"private_constant",
|
459
|
+
"private_instance_methods",
|
460
|
+
"protected_instance_methods",
|
461
|
+
"public_class_method",
|
462
|
+
"public_instance_method",
|
463
|
+
"public_instance_methods",
|
464
|
+
"remove_class_variable",
|
465
|
+
"constants",
|
466
|
+
"nesting",
|
467
|
+
"ancestors",
|
468
|
+
"autoload",
|
469
|
+
"class_eval",
|
470
|
+
"class_exec",
|
471
|
+
"class_variable_get",
|
472
|
+
"class_variable_set",
|
473
|
+
"class_variables",
|
474
|
+
"const_get",
|
475
|
+
"const_set",
|
476
|
+
"const_missing",
|
477
|
+
"deprecate_constants",
|
478
|
+
"method_added",
|
479
|
+
"method_removed",
|
480
|
+
"method_undefined",
|
481
|
+
"method_function",
|
482
|
+
"prepend_features",
|
483
|
+
"prepended",
|
484
|
+
"private",
|
485
|
+
"refine",
|
486
|
+
"remove_const",
|
487
|
+
"remove_method",
|
488
|
+
"undef_method",
|
489
|
+
"using",
|
490
|
+
])
|
491
|
+
|
492
|
+
BLACKLISTED_REPL_METHODS = Set.new([
|
493
|
+
"pry",
|
494
|
+
"binding",
|
495
|
+
"__binding__",
|
496
|
+
"remote_pry",
|
497
|
+
"remote_pray",
|
498
|
+
"pry_remote",
|
499
|
+
"pray_remote"
|
500
|
+
])
|
501
|
+
|
502
|
+
def kill_instance_methods(obj, msg)
|
503
|
+
if [ "object_id", "__id__" ].include?(msg)
|
504
|
+
return
|
505
|
+
end
|
506
|
+
|
507
|
+
if obj.is_a?(DRabUndumped)
|
508
|
+
if obj.class.class_variable_get(:@@drab_whitelist).include?("to_s")
|
509
|
+
if msg === "respond_to?"
|
510
|
+
return
|
511
|
+
end
|
512
|
+
end
|
513
|
+
if obj.class.class_variable_get(:@@drab_whitelist).include?(msg)
|
514
|
+
return
|
515
|
+
else
|
516
|
+
puts "unwhitelisted method call attempted: #{msg} on" + obj.class.to_s
|
517
|
+
raise Exception.new("unwhitelisted method call attempted")
|
518
|
+
end
|
519
|
+
end
|
520
|
+
|
521
|
+
if BLACKLISTED_BASIC_OBJECT_METHODS.include?(msg)
|
522
|
+
puts "dangerous BasicObject method called: #{msg} on " + obj.class.to_s
|
523
|
+
raise Exception.new("dangerous BasicObject method called")
|
524
|
+
end
|
525
|
+
|
526
|
+
if BLACKLISTED_MODULE_METHODS.include?(msg)
|
527
|
+
puts "dangerous Module method called: #{msg} on " + obj.class.to_s
|
528
|
+
raise Exception.new("dangerous Module method called")
|
529
|
+
end
|
530
|
+
|
531
|
+
if BLACKLISTED_REPL_METHODS.include?(msg)
|
532
|
+
puts "dangerous repl method called: #{msg} on " + obj.class.to_s
|
533
|
+
raise Exception.new("dangerous repl method called")
|
534
|
+
end
|
535
|
+
|
536
|
+
end
|
537
|
+
|
538
|
+
# jtd: adding symkey auth here
|
539
|
+
|
540
|
+
def send_secret(stream)
|
541
|
+
if DRab.current_server.secret != nil
|
542
|
+
shared_secret = DRab.current_server.secret
|
543
|
+
stream.write([shared_secret.size].pack('N') + shared_secret)
|
544
|
+
end
|
545
|
+
end
|
546
|
+
|
547
|
+
# taken from rails/ActiveSupport/MessageVerifier/secure_compare
|
548
|
+
def secure_compare(a, b)
|
549
|
+
return false unless a.bytesize == b.bytesize
|
550
|
+
|
551
|
+
l = a.unpack "C#{a.bytesize}"
|
552
|
+
|
553
|
+
res = 0
|
554
|
+
b.each_byte { |byte| res |= byte ^ l.shift }
|
555
|
+
res == 0
|
556
|
+
end
|
557
|
+
|
558
|
+
def recv_secret(stream)
|
559
|
+
if DRab.current_server.secret != nil
|
560
|
+
shared_secret = DRab.current_server.secret
|
561
|
+
received_secret = nil
|
562
|
+
|
563
|
+
begin
|
564
|
+
sz = stream.read(4)
|
565
|
+
rescue
|
566
|
+
raise(DRabConnError, $!.message, $!.backtrace)
|
567
|
+
end
|
568
|
+
raise(DRabConnError, 'connection closed') if sz.nil?
|
569
|
+
raise(DRabConnError, 'secret size wrong size') if sz.size != 4
|
570
|
+
sz = sz.unpack('N')[0]
|
571
|
+
raise(DRabConnError, 'secret size wrong') if sz != shared_secret.size
|
572
|
+
begin
|
573
|
+
received_secret = stream.read(sz)
|
574
|
+
rescue
|
575
|
+
raise(DRabConnError, $!.message, $!.backtrace)
|
576
|
+
end
|
577
|
+
raise(DRabConnError, 'connection closed') if received_secret.nil?
|
578
|
+
raise(DRabConnError, 'premature secret (can\'t read)') if received_secret.size < sz
|
579
|
+
|
580
|
+
if received_secret.length != shared_secret.length
|
581
|
+
stream.close
|
582
|
+
elsif !secure_compare(shared_secret, received_secret)
|
583
|
+
stream.close
|
584
|
+
end
|
585
|
+
end
|
586
|
+
end
|
587
|
+
# /jtd
|
588
|
+
|
589
|
+
def recv_request(stream)
|
590
|
+
recv_secret(stream)
|
591
|
+
ref = load(stream, true)
|
592
|
+
if not ref.is_a? Integer and not ref.is_a? NilClass
|
593
|
+
raise Exception.new "non-numeric ref id"
|
594
|
+
end
|
595
|
+
ro = DRab.to_obj(ref)
|
596
|
+
|
597
|
+
msg = load(stream, true)
|
598
|
+
if not msg.is_a? String
|
599
|
+
raise Exception.new "non-string msg name"
|
600
|
+
end
|
601
|
+
|
602
|
+
#note: obviously, blacklisting a few things is not enough, we also need
|
603
|
+
# to make sure that arbitrary objects can't just be wrapped by id
|
604
|
+
# or deserialized, and maybe do to limit the sorts of
|
605
|
+
# objects that can be passed to only primative or "DRab-aware" types.
|
606
|
+
kill_instance_methods(ro, msg)
|
607
|
+
|
608
|
+
argc = load(stream, true)
|
609
|
+
if not argc.is_a? Integer
|
610
|
+
raise Exception.new "non-numeric argc"
|
611
|
+
end
|
612
|
+
raise(DRabConnError, "too many arguments") if @argc_limit < argc
|
613
|
+
argv = Array.new(argc, nil)
|
614
|
+
argc.times do |n|
|
615
|
+
argv[n] = load(stream)
|
616
|
+
end
|
617
|
+
block = nil
|
618
|
+
|
619
|
+
return ro, msg, argv, block
|
620
|
+
end
|
621
|
+
|
622
|
+
def send_reply(stream, succ, result)
|
623
|
+
send_secret(stream)
|
624
|
+
stream.write(dump(succ) + dump(result, !succ))
|
625
|
+
rescue
|
626
|
+
raise(DRabConnError, $!.message, $!.backtrace)
|
627
|
+
end
|
628
|
+
|
629
|
+
def recv_reply(stream)
|
630
|
+
recv_secret(stream)
|
631
|
+
succ = load(stream)
|
632
|
+
result = load(stream)
|
633
|
+
if result.is_a?(DRabArray::Token)
|
634
|
+
r = result.size.times.collect {|| load(stream) }
|
635
|
+
[succ, r]
|
636
|
+
else
|
637
|
+
[succ, result]
|
638
|
+
end
|
639
|
+
end
|
640
|
+
|
641
|
+
private
|
642
|
+
def make_proxy(obj, error=false)
|
643
|
+
if error
|
644
|
+
DRabRemoteError.new(obj)
|
645
|
+
else
|
646
|
+
DRabObject.new(obj)
|
647
|
+
end
|
648
|
+
end
|
649
|
+
end
|
650
|
+
|
651
|
+
module DRabProtocol
|
652
|
+
|
653
|
+
def add_protocol(prot)
|
654
|
+
@protocol.push(prot)
|
655
|
+
end
|
656
|
+
module_function :add_protocol
|
657
|
+
|
658
|
+
def open(uri, config, first=true)
|
659
|
+
@protocol.each do |prot|
|
660
|
+
begin
|
661
|
+
return prot.open(uri, config)
|
662
|
+
rescue DRabBadScheme
|
663
|
+
rescue DRabConnError
|
664
|
+
raise($!)
|
665
|
+
rescue
|
666
|
+
raise(DRabConnError, "#{uri} - #{$!.inspect}")
|
667
|
+
end
|
668
|
+
end
|
669
|
+
if first && (config[:auto_load] != false)
|
670
|
+
auto_load(uri)
|
671
|
+
return open(uri, config, false)
|
672
|
+
end
|
673
|
+
raise DRabBadURI, 'can\'t parse uri:' + uri
|
674
|
+
end
|
675
|
+
module_function :open
|
676
|
+
|
677
|
+
def open_server(uri, config, first=true)
|
678
|
+
@protocol.each do |prot|
|
679
|
+
begin
|
680
|
+
return prot.open_server(uri, config)
|
681
|
+
rescue DRabBadScheme
|
682
|
+
end
|
683
|
+
end
|
684
|
+
if first && (config[:auto_load] != false)
|
685
|
+
auto_load(uri)
|
686
|
+
return open_server(uri, config, false)
|
687
|
+
end
|
688
|
+
raise DRabBadURI, 'can\'t parse uri:' + uri
|
689
|
+
end
|
690
|
+
module_function :open_server
|
691
|
+
|
692
|
+
def uri_option(uri, config, first=true)
|
693
|
+
@protocol.each do |prot|
|
694
|
+
begin
|
695
|
+
uri, opt = prot.uri_option(uri, config)
|
696
|
+
# opt = nil if opt == ''
|
697
|
+
return uri, opt
|
698
|
+
rescue DRabBadScheme
|
699
|
+
end
|
700
|
+
end
|
701
|
+
if first && (config[:auto_load] != false)
|
702
|
+
auto_load(uri)
|
703
|
+
return uri_option(uri, config, false)
|
704
|
+
end
|
705
|
+
raise DRabBadURI, 'can\'t parse uri:' + uri
|
706
|
+
end
|
707
|
+
module_function :uri_option
|
708
|
+
|
709
|
+
def auto_load(uri) # :nodoc:
|
710
|
+
if uri =~ /^drab([a-z0-9]+):/
|
711
|
+
require("drab/#{$1}") rescue nil
|
712
|
+
end
|
713
|
+
end
|
714
|
+
module_function :auto_load
|
715
|
+
end
|
716
|
+
|
717
|
+
class DRabTCPSocket
|
718
|
+
private
|
719
|
+
def self.parse_uri(uri)
|
720
|
+
if uri =~ /^druby:\/\/(.*?):(\d+)(\?(.*))?$/
|
721
|
+
host = $1
|
722
|
+
port = $2.to_i
|
723
|
+
option = $4
|
724
|
+
[host, port, option]
|
725
|
+
else
|
726
|
+
raise(DRabBadScheme, uri) unless uri =~ /^druby:/
|
727
|
+
raise(DRabBadURI, 'can\'t parse uri:' + uri)
|
728
|
+
end
|
729
|
+
end
|
730
|
+
|
731
|
+
public
|
732
|
+
|
733
|
+
def self.open(uri, config)
|
734
|
+
host, port, = parse_uri(uri)
|
735
|
+
host.untaint
|
736
|
+
port.untaint
|
737
|
+
soc = TCPSocket.open(host, port)
|
738
|
+
self.new(uri, soc, config)
|
739
|
+
end
|
740
|
+
|
741
|
+
def self.getservername
|
742
|
+
host = Socket::gethostname
|
743
|
+
begin
|
744
|
+
Socket::gethostbyname(host)[0]
|
745
|
+
rescue
|
746
|
+
'localhost'
|
747
|
+
end
|
748
|
+
end
|
749
|
+
|
750
|
+
def self.open_server_inaddr_any(host, port)
|
751
|
+
infos = Socket::getaddrinfo(host, nil,
|
752
|
+
Socket::AF_UNSPEC,
|
753
|
+
Socket::SOCK_STREAM,
|
754
|
+
0,
|
755
|
+
Socket::AI_PASSIVE)
|
756
|
+
families = Hash[*infos.collect { |af, *_| af }.uniq.zip([]).flatten]
|
757
|
+
return TCPServer.open('0.0.0.0', port) if families.has_key?('AF_INET')
|
758
|
+
return TCPServer.open('::', port) if families.has_key?('AF_INET6')
|
759
|
+
return TCPServer.open(port)
|
760
|
+
end
|
761
|
+
|
762
|
+
def self.open_server(uri, config)
|
763
|
+
uri = 'druby://:0' unless uri
|
764
|
+
host, port, _ = parse_uri(uri)
|
765
|
+
config = {:tcp_original_host => host}.update(config)
|
766
|
+
if host.size == 0
|
767
|
+
host = getservername
|
768
|
+
soc = open_server_inaddr_any(host, port)
|
769
|
+
else
|
770
|
+
soc = TCPServer.open(host, port)
|
771
|
+
end
|
772
|
+
port = soc.addr[1] if port == 0
|
773
|
+
config[:tcp_port] = port
|
774
|
+
uri = "druby://#{host}:#{port}"
|
775
|
+
self.new(uri, soc, config)
|
776
|
+
end
|
777
|
+
|
778
|
+
def self.uri_option(uri, config)
|
779
|
+
host, port, option = parse_uri(uri)
|
780
|
+
return "druby://#{host}:#{port}", option
|
781
|
+
end
|
782
|
+
|
783
|
+
def initialize(uri, soc, config={})
|
784
|
+
@uri = uri
|
785
|
+
@socket = soc
|
786
|
+
@config = config
|
787
|
+
@acl = config[:tcp_acl]
|
788
|
+
@msg = DRabMessage.new(config)
|
789
|
+
set_sockopt(@socket)
|
790
|
+
@shutdown_pipe_r, @shutdown_pipe_w = IO.pipe
|
791
|
+
end
|
792
|
+
|
793
|
+
attr_reader :uri
|
794
|
+
|
795
|
+
def peeraddr
|
796
|
+
@socket.peeraddr
|
797
|
+
end
|
798
|
+
|
799
|
+
def stream; @socket; end
|
800
|
+
|
801
|
+
def send_request(ref, msg_id, arg, b)
|
802
|
+
@msg.send_request(stream, ref, msg_id, arg, b)
|
803
|
+
end
|
804
|
+
|
805
|
+
def recv_request
|
806
|
+
@msg.recv_request(stream)
|
807
|
+
end
|
808
|
+
|
809
|
+
def send_reply(succ, result)
|
810
|
+
@msg.send_reply(stream, succ, result)
|
811
|
+
end
|
812
|
+
|
813
|
+
def recv_reply
|
814
|
+
@msg.recv_reply(stream)
|
815
|
+
end
|
816
|
+
|
817
|
+
public
|
818
|
+
|
819
|
+
def close
|
820
|
+
if @socket
|
821
|
+
@socket.close
|
822
|
+
@socket = nil
|
823
|
+
end
|
824
|
+
close_shutdown_pipe
|
825
|
+
end
|
826
|
+
|
827
|
+
def close_shutdown_pipe
|
828
|
+
if @shutdown_pipe_r && !@shutdown_pipe_r.closed?
|
829
|
+
@shutdown_pipe_r.close
|
830
|
+
@shutdown_pipe_r = nil
|
831
|
+
end
|
832
|
+
if @shutdown_pipe_w && !@shutdown_pipe_w.closed?
|
833
|
+
@shutdown_pipe_w.close
|
834
|
+
@shutdown_pipe_w = nil
|
835
|
+
end
|
836
|
+
end
|
837
|
+
private :close_shutdown_pipe
|
838
|
+
|
839
|
+
def accept
|
840
|
+
while true
|
841
|
+
s = accept_or_shutdown
|
842
|
+
return nil unless s
|
843
|
+
break if (@acl ? @acl.allow_socket?(s) : true)
|
844
|
+
s.close
|
845
|
+
end
|
846
|
+
if @config[:tcp_original_host].to_s.size == 0
|
847
|
+
uri = "druby://#{s.addr[3]}:#{@config[:tcp_port]}"
|
848
|
+
else
|
849
|
+
uri = @uri
|
850
|
+
end
|
851
|
+
|
852
|
+
self.class.new(uri, s, @config)
|
853
|
+
end
|
854
|
+
|
855
|
+
def accept_or_shutdown
|
856
|
+
readables, = IO.select([@socket, @shutdown_pipe_r])
|
857
|
+
if readables.include? @shutdown_pipe_r
|
858
|
+
return nil
|
859
|
+
end
|
860
|
+
@socket.accept
|
861
|
+
end
|
862
|
+
private :accept_or_shutdown
|
863
|
+
|
864
|
+
def shutdown
|
865
|
+
@shutdown_pipe_w.close if @shutdown_pipe_w && !@shutdown_pipe_w.closed?
|
866
|
+
end
|
867
|
+
|
868
|
+
def alive?
|
869
|
+
return false unless @socket
|
870
|
+
if IO.select([@socket], nil, nil, 0)
|
871
|
+
#if @socket.to_io.wait_readable(0)
|
872
|
+
close
|
873
|
+
return false
|
874
|
+
end
|
875
|
+
true
|
876
|
+
end
|
877
|
+
|
878
|
+
def set_sockopt(soc)
|
879
|
+
soc.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
|
880
|
+
end
|
881
|
+
end
|
882
|
+
|
883
|
+
module DRabProtocol
|
884
|
+
@protocol = [DRabTCPSocket] # default
|
885
|
+
end
|
886
|
+
|
887
|
+
# class DRabURIOption # :nodoc: I don't understand the purpose of this class... # <-- which is why it shouldn't exist
|
888
|
+
# def initialize(option)
|
889
|
+
# @option = option.to_s
|
890
|
+
# end
|
891
|
+
# attr_reader :option
|
892
|
+
# def to_s; @option; end
|
893
|
+
#
|
894
|
+
# def ==(other)
|
895
|
+
# return false unless DRabURIOption === other
|
896
|
+
# @option == other.option
|
897
|
+
# end
|
898
|
+
#
|
899
|
+
# def hash
|
900
|
+
# @option.hash
|
901
|
+
# end
|
902
|
+
#
|
903
|
+
# alias eql? ==
|
904
|
+
# end
|
905
|
+
|
906
|
+
class DRabObject
|
907
|
+
def self._load(s)
|
908
|
+
#uri, ref = Marshal::load(s)
|
909
|
+
uri, ref = JSON::load(s)
|
910
|
+
|
911
|
+
if DRab.here?(uri)
|
912
|
+
obj = DRab.to_obj(ref)
|
913
|
+
if ((! obj.tainted?) && Thread.current[:drab_untaint])
|
914
|
+
Thread.current[:drab_untaint].push(obj)
|
915
|
+
end
|
916
|
+
return obj
|
917
|
+
end
|
918
|
+
|
919
|
+
self.new_with(uri, ref)
|
920
|
+
end
|
921
|
+
|
922
|
+
def self.new_with(uri, ref)
|
923
|
+
it = self.allocate
|
924
|
+
it.instance_variable_set(:@uri, uri)
|
925
|
+
it.instance_variable_set(:@ref, ref)
|
926
|
+
it
|
927
|
+
end
|
928
|
+
|
929
|
+
def self.new_with_uri(uri)
|
930
|
+
self.new(nil, uri)
|
931
|
+
end
|
932
|
+
|
933
|
+
def _dump(lv)
|
934
|
+
#Marshal::dump([@uri, @ref])
|
935
|
+
JSON::dump([@uri, @ref])
|
936
|
+
end
|
937
|
+
|
938
|
+
def initialize(obj, uri=nil)
|
939
|
+
@uri = nil
|
940
|
+
@ref = nil
|
941
|
+
if obj.nil?
|
942
|
+
return if uri.nil?
|
943
|
+
@uri, option = DRabProtocol.uri_option(uri, DRab.config)
|
944
|
+
#@ref = DRabURIOption.new(option) unless option.nil?
|
945
|
+
@ref = option.to_s unless option.nil?
|
946
|
+
else
|
947
|
+
@uri = uri ? uri : (DRab.uri rescue nil)
|
948
|
+
@ref = obj ? DRab.to_id(obj) : nil
|
949
|
+
end
|
950
|
+
end
|
951
|
+
|
952
|
+
def __draburi
|
953
|
+
@uri
|
954
|
+
end
|
955
|
+
|
956
|
+
def __drabref
|
957
|
+
@ref
|
958
|
+
end
|
959
|
+
|
960
|
+
undef :to_s
|
961
|
+
undef :to_a if respond_to?(:to_a)
|
962
|
+
|
963
|
+
def respond_to?(msg_id, priv=false)
|
964
|
+
case msg_id
|
965
|
+
when :_dump
|
966
|
+
true
|
967
|
+
when :marshal_dump
|
968
|
+
false
|
969
|
+
else
|
970
|
+
method_missing(:respond_to?, msg_id, priv)
|
971
|
+
end
|
972
|
+
end
|
973
|
+
|
974
|
+
def method_missing(msg_id, *a, &b)
|
975
|
+
if DRab.here?(@uri)
|
976
|
+
obj = DRab.to_obj(@ref)
|
977
|
+
DRab.current_server.check_insecure_method(obj, msg_id)
|
978
|
+
return obj.__send__(msg_id, *a, &b)
|
979
|
+
end
|
980
|
+
|
981
|
+
succ, result = self.class.with_friend(@uri) do
|
982
|
+
DRabConn.open(@uri) do |conn|
|
983
|
+
suc, res = conn.send_message(self, msg_id, a, b)
|
984
|
+
end
|
985
|
+
end
|
986
|
+
|
987
|
+
if succ
|
988
|
+
return result
|
989
|
+
elsif DRabUnknown === result
|
990
|
+
raise result
|
991
|
+
else
|
992
|
+
bt = self.class.prepare_backtrace(@uri, result)
|
993
|
+
result.set_backtrace(bt + caller)
|
994
|
+
raise result
|
995
|
+
end
|
996
|
+
end
|
997
|
+
|
998
|
+
def self.with_friend(uri)
|
999
|
+
friend = DRab.fetch_server(uri)
|
1000
|
+
return yield() unless friend
|
1001
|
+
|
1002
|
+
save = Thread.current['DRab']
|
1003
|
+
Thread.current['DRab'] = { 'server' => friend }
|
1004
|
+
return yield
|
1005
|
+
ensure
|
1006
|
+
Thread.current['DRab'] = save if friend
|
1007
|
+
end
|
1008
|
+
|
1009
|
+
def self.prepare_backtrace(uri, result)
|
1010
|
+
prefix = "(#{uri}) "
|
1011
|
+
bt = []
|
1012
|
+
result.backtrace.each do |x|
|
1013
|
+
break if /`__send__'$/ =~ x
|
1014
|
+
if /^\(druby:\/\// =~ x
|
1015
|
+
bt.push(x)
|
1016
|
+
else
|
1017
|
+
bt.push(prefix + x)
|
1018
|
+
end
|
1019
|
+
end
|
1020
|
+
bt
|
1021
|
+
end
|
1022
|
+
|
1023
|
+
def pretty_print(q)
|
1024
|
+
q.pp_object(self)
|
1025
|
+
end
|
1026
|
+
|
1027
|
+
def pretty_print_cycle(q)
|
1028
|
+
q.object_address_group(self) {
|
1029
|
+
q.breakable
|
1030
|
+
q.text '...'
|
1031
|
+
}
|
1032
|
+
end
|
1033
|
+
end
|
1034
|
+
|
1035
|
+
class DRabConn
|
1036
|
+
POOL_SIZE = 16
|
1037
|
+
#@mutex = Thread::Mutex.new
|
1038
|
+
@mutex = Mutex.new
|
1039
|
+
@pool = []
|
1040
|
+
|
1041
|
+
def self.open(remote_uri)
|
1042
|
+
begin
|
1043
|
+
conn = nil
|
1044
|
+
|
1045
|
+
@mutex.synchronize do
|
1046
|
+
#FIXME
|
1047
|
+
new_pool = []
|
1048
|
+
@pool.each do |c|
|
1049
|
+
if conn.nil? and c.uri == remote_uri
|
1050
|
+
conn = c if c.alive?
|
1051
|
+
else
|
1052
|
+
new_pool.push c
|
1053
|
+
end
|
1054
|
+
end
|
1055
|
+
@pool = new_pool
|
1056
|
+
end
|
1057
|
+
|
1058
|
+
conn = self.new(remote_uri) unless conn
|
1059
|
+
succ, result = yield(conn)
|
1060
|
+
return succ, result
|
1061
|
+
|
1062
|
+
ensure
|
1063
|
+
if conn
|
1064
|
+
if succ
|
1065
|
+
@mutex.synchronize do
|
1066
|
+
@pool.unshift(conn)
|
1067
|
+
@pool.pop.close while @pool.size > POOL_SIZE
|
1068
|
+
end
|
1069
|
+
else
|
1070
|
+
conn.close
|
1071
|
+
end
|
1072
|
+
end
|
1073
|
+
end
|
1074
|
+
end
|
1075
|
+
|
1076
|
+
def initialize(remote_uri)
|
1077
|
+
@uri = remote_uri
|
1078
|
+
@protocol = DRabProtocol.open(remote_uri, DRab.config)
|
1079
|
+
end
|
1080
|
+
attr_reader :uri
|
1081
|
+
|
1082
|
+
def send_message(ref, msg_id, arg, block)
|
1083
|
+
@protocol.send_request(ref, msg_id, arg, block)
|
1084
|
+
@protocol.recv_reply
|
1085
|
+
end
|
1086
|
+
|
1087
|
+
def close
|
1088
|
+
@protocol.close
|
1089
|
+
@protocol = nil
|
1090
|
+
end
|
1091
|
+
|
1092
|
+
def alive?
|
1093
|
+
return false unless @protocol
|
1094
|
+
@protocol.alive?
|
1095
|
+
end
|
1096
|
+
end
|
1097
|
+
|
1098
|
+
class DRabServer
|
1099
|
+
@@acl = nil
|
1100
|
+
@@idconv = DRabIdConv.new
|
1101
|
+
@@secondary_server = nil
|
1102
|
+
@@argc_limit = 256
|
1103
|
+
@@load_limit = 256 * 102400
|
1104
|
+
@@verbose = false
|
1105
|
+
@@safe_level = 0
|
1106
|
+
|
1107
|
+
def self.default_argc_limit(argc)
|
1108
|
+
@@argc_limit = argc
|
1109
|
+
end
|
1110
|
+
|
1111
|
+
def self.default_load_limit(sz)
|
1112
|
+
@@load_limit = sz
|
1113
|
+
end
|
1114
|
+
|
1115
|
+
def self.default_acl(acl)
|
1116
|
+
@@acl = acl
|
1117
|
+
end
|
1118
|
+
|
1119
|
+
def self.default_safe_level(level)
|
1120
|
+
@@safe_level = level
|
1121
|
+
end
|
1122
|
+
|
1123
|
+
def self.verbose=(on)
|
1124
|
+
@@verbose = on
|
1125
|
+
end
|
1126
|
+
|
1127
|
+
def self.verbose
|
1128
|
+
@@verbose
|
1129
|
+
end
|
1130
|
+
|
1131
|
+
def self.make_config(hash={})
|
1132
|
+
default_config = {
|
1133
|
+
:verbose => @@verbose,
|
1134
|
+
:tcp_acl => @@acl,
|
1135
|
+
:load_limit => @@load_limit,
|
1136
|
+
:argc_limit => @@argc_limit,
|
1137
|
+
:safe_level => @@safe_level,
|
1138
|
+
:secret => nil
|
1139
|
+
}
|
1140
|
+
default_config.update(hash)
|
1141
|
+
end
|
1142
|
+
|
1143
|
+
def initialize(uri=nil, front=nil, config_or_acl=nil)
|
1144
|
+
if Hash === config_or_acl
|
1145
|
+
config = config_or_acl.dup
|
1146
|
+
else
|
1147
|
+
acl = config_or_acl || @@acl
|
1148
|
+
config = {
|
1149
|
+
:tcp_acl => acl
|
1150
|
+
}
|
1151
|
+
end
|
1152
|
+
|
1153
|
+
@config = self.class.make_config(config)
|
1154
|
+
|
1155
|
+
@protocol = DRabProtocol.open_server(uri, @config)
|
1156
|
+
@uri = @protocol.uri
|
1157
|
+
@exported_uri = [@uri]
|
1158
|
+
@secret = @config[:secret]
|
1159
|
+
|
1160
|
+
@front = front
|
1161
|
+
@idconv = @@idconv
|
1162
|
+
@safe_level = @config[:safe_level]
|
1163
|
+
|
1164
|
+
@grp = ThreadGroup.new
|
1165
|
+
@thread = run
|
1166
|
+
|
1167
|
+
DRab.regist_server(self)
|
1168
|
+
end
|
1169
|
+
|
1170
|
+
attr_reader :uri
|
1171
|
+
|
1172
|
+
attr_reader :secret
|
1173
|
+
|
1174
|
+
attr_reader :thread
|
1175
|
+
|
1176
|
+
attr_reader :front
|
1177
|
+
|
1178
|
+
attr_reader :config
|
1179
|
+
|
1180
|
+
attr_reader :safe_level
|
1181
|
+
|
1182
|
+
def verbose=(v); @config[:verbose]=v; end
|
1183
|
+
|
1184
|
+
def verbose; @config[:verbose]; end
|
1185
|
+
|
1186
|
+
def alive?
|
1187
|
+
@thread.alive?
|
1188
|
+
end
|
1189
|
+
|
1190
|
+
def here?(uri)
|
1191
|
+
@exported_uri.include?(uri)
|
1192
|
+
end
|
1193
|
+
|
1194
|
+
def stop_service
|
1195
|
+
DRab.remove_server(self)
|
1196
|
+
if Thread.current['DRab'] && Thread.current['DRab']['server'] == self
|
1197
|
+
Thread.current['DRab']['stop_service'] = true
|
1198
|
+
else
|
1199
|
+
if @protocol.respond_to? :shutdown
|
1200
|
+
@protocol.shutdown
|
1201
|
+
else
|
1202
|
+
[@thread, *@grp.list].each {|thread| thread.kill}
|
1203
|
+
end
|
1204
|
+
@thread.join
|
1205
|
+
end
|
1206
|
+
end
|
1207
|
+
|
1208
|
+
def to_obj(ref)
|
1209
|
+
return front if ref.nil?
|
1210
|
+
#return front[ref.to_s] if DRabURIOption === ref
|
1211
|
+
return front[ref] if ref.is_a? String
|
1212
|
+
@idconv.to_obj(ref)
|
1213
|
+
end
|
1214
|
+
|
1215
|
+
def to_id(obj)
|
1216
|
+
return nil if obj.__id__ == front.__id__
|
1217
|
+
@idconv.to_id(obj)
|
1218
|
+
end
|
1219
|
+
|
1220
|
+
|
1221
|
+
private
|
1222
|
+
|
1223
|
+
def run
|
1224
|
+
Thread.start do
|
1225
|
+
begin
|
1226
|
+
while main_loop
|
1227
|
+
end
|
1228
|
+
ensure
|
1229
|
+
@protocol.close if @protocol
|
1230
|
+
end
|
1231
|
+
end
|
1232
|
+
end
|
1233
|
+
|
1234
|
+
# List of insecure methods. # it's a list of "insecure method" (singular)
|
1235
|
+
#
|
1236
|
+
# These methods are not callable via dRuby. # you say that, but :send was allowed. that and a bunch of other dangerous stuff.
|
1237
|
+
INSECURE_METHOD = [
|
1238
|
+
:__send__
|
1239
|
+
]
|
1240
|
+
|
1241
|
+
def insecure_method?(msg_id)
|
1242
|
+
INSECURE_METHOD.include?(msg_id)
|
1243
|
+
end
|
1244
|
+
|
1245
|
+
def any_to_s(obj)
|
1246
|
+
obj.to_s + ":#{obj.class}"
|
1247
|
+
rescue
|
1248
|
+
sprintf("#<%s:0x%lx>", obj.class, obj.__id__)
|
1249
|
+
end
|
1250
|
+
|
1251
|
+
def check_insecure_method(obj, msg_id)
|
1252
|
+
return true if Proc === obj && msg_id == :__drab_yield
|
1253
|
+
raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class
|
1254
|
+
raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id)
|
1255
|
+
|
1256
|
+
if obj.private_methods.include?(msg_id)
|
1257
|
+
desc = any_to_s(obj)
|
1258
|
+
raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
|
1259
|
+
elsif obj.protected_methods.include?(msg_id)
|
1260
|
+
desc = any_to_s(obj)
|
1261
|
+
raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
|
1262
|
+
else
|
1263
|
+
true
|
1264
|
+
end
|
1265
|
+
end
|
1266
|
+
public :check_insecure_method
|
1267
|
+
|
1268
|
+
class InvokeMethod
|
1269
|
+
def initialize(drab_server, client)
|
1270
|
+
@drab_server = drab_server
|
1271
|
+
@safe_level = drab_server.safe_level
|
1272
|
+
@client = client
|
1273
|
+
end
|
1274
|
+
|
1275
|
+
def perform
|
1276
|
+
@result = nil
|
1277
|
+
@succ = false
|
1278
|
+
setup_message
|
1279
|
+
|
1280
|
+
if $SAFE < @safe_level
|
1281
|
+
info = Thread.current['DRab']
|
1282
|
+
@result = Thread.new {
|
1283
|
+
Thread.current['DRab'] = info
|
1284
|
+
$SAFE = @safe_level
|
1285
|
+
perform_without_block
|
1286
|
+
}.value
|
1287
|
+
else
|
1288
|
+
@result = perform_without_block
|
1289
|
+
end
|
1290
|
+
@succ = true
|
1291
|
+
if @result.class == Array
|
1292
|
+
@result = DRabArray.new(@result)
|
1293
|
+
end
|
1294
|
+
return @succ, @result
|
1295
|
+
rescue StandardError, ScriptError, Interrupt
|
1296
|
+
@result = $!
|
1297
|
+
return @succ, @result
|
1298
|
+
end
|
1299
|
+
|
1300
|
+
private
|
1301
|
+
def init_with_client
|
1302
|
+
obj, msg, argv, block = @client.recv_request
|
1303
|
+
@obj = obj
|
1304
|
+
@msg_id = msg.intern
|
1305
|
+
@argv = argv
|
1306
|
+
@block = block
|
1307
|
+
end
|
1308
|
+
|
1309
|
+
def check_insecure_method
|
1310
|
+
@drab_server.check_insecure_method(@obj, @msg_id)
|
1311
|
+
end
|
1312
|
+
|
1313
|
+
def setup_message
|
1314
|
+
init_with_client
|
1315
|
+
check_insecure_method
|
1316
|
+
end
|
1317
|
+
|
1318
|
+
def perform_without_block
|
1319
|
+
#STDOUT.puts @obj.class.to_s + "::" + @msg_id.to_s
|
1320
|
+
if Proc === @obj && @msg_id == :__drab_yield
|
1321
|
+
if @argv.size == 1
|
1322
|
+
ary = @argv
|
1323
|
+
else
|
1324
|
+
ary = [@argv]
|
1325
|
+
end
|
1326
|
+
ary.collect(&@obj)[0]
|
1327
|
+
elsif Proc === @obj and @msg_id != :call
|
1328
|
+
STDERR.puts "spooky proc call of " + @msg_id.to_s
|
1329
|
+
raise Exception.new "spooky proc call of " + @msg_id.to_s
|
1330
|
+
else
|
1331
|
+
if @obj.class.method_defined?(@msg_id)
|
1332
|
+
@obj.__send__(@msg_id, *@argv)
|
1333
|
+
else
|
1334
|
+
STDERR.puts "spooky call of " + @msg_id.to_s + " on " + @obj.class.to_s
|
1335
|
+
raise Exception.new "spooky call of " + @msg_id.to_s + " on " + @obj.class.to_s
|
1336
|
+
end
|
1337
|
+
end
|
1338
|
+
end
|
1339
|
+
end
|
1340
|
+
|
1341
|
+
require 'drab/invokemethod'
|
1342
|
+
class InvokeMethod
|
1343
|
+
include InvokeMethod18Mixin
|
1344
|
+
end
|
1345
|
+
|
1346
|
+
def error_print(exception)
|
1347
|
+
exception.backtrace.inject(true) do |first, x|
|
1348
|
+
if first
|
1349
|
+
STDERR.puts "#{x}: #{exception} (#{exception.class})"
|
1350
|
+
else
|
1351
|
+
STDERR.puts "\tfrom #{x}"
|
1352
|
+
end
|
1353
|
+
false
|
1354
|
+
end
|
1355
|
+
end
|
1356
|
+
|
1357
|
+
def main_loop
|
1358
|
+
client0 = @protocol.accept
|
1359
|
+
return nil if !client0
|
1360
|
+
Thread.start(client0) do |client|
|
1361
|
+
@grp.add Thread.current
|
1362
|
+
Thread.current['DRab'] = { 'client' => client ,
|
1363
|
+
'server' => self }
|
1364
|
+
DRab.mutex.synchronize do
|
1365
|
+
client_uri = client.uri
|
1366
|
+
@exported_uri << client_uri unless @exported_uri.include?(client_uri)
|
1367
|
+
end
|
1368
|
+
loop do
|
1369
|
+
begin
|
1370
|
+
succ = false
|
1371
|
+
invoke_method = InvokeMethod.new(self, client)
|
1372
|
+
succ, result = invoke_method.perform
|
1373
|
+
error_print(result) if !succ && verbose
|
1374
|
+
client.send_reply(succ, result)
|
1375
|
+
rescue Exception => e
|
1376
|
+
error_print(e) if verbose
|
1377
|
+
ensure
|
1378
|
+
client.close unless succ
|
1379
|
+
if Thread.current['DRab']['stop_service']
|
1380
|
+
Thread.new { stop_service }
|
1381
|
+
end
|
1382
|
+
break unless succ
|
1383
|
+
end
|
1384
|
+
end
|
1385
|
+
end
|
1386
|
+
end
|
1387
|
+
end
|
1388
|
+
|
1389
|
+
@primary_server = nil
|
1390
|
+
|
1391
|
+
def start_service(uri=nil, front=nil, config=nil)
|
1392
|
+
if config == nil
|
1393
|
+
config = {}
|
1394
|
+
end
|
1395
|
+
if uri.include? "?secret="
|
1396
|
+
uri, secret = uri.split("?secret=")
|
1397
|
+
config[:secret] = secret
|
1398
|
+
end
|
1399
|
+
|
1400
|
+
@primary_server = DRabServer.new(uri, front, config)
|
1401
|
+
end
|
1402
|
+
module_function :start_service
|
1403
|
+
|
1404
|
+
attr_accessor :primary_server
|
1405
|
+
module_function :primary_server=, :primary_server
|
1406
|
+
|
1407
|
+
def current_server
|
1408
|
+
drab = Thread.current['DRab']
|
1409
|
+
server = (drab && drab['server']) ? drab['server'] : @primary_server
|
1410
|
+
raise DRabServerNotFound unless server
|
1411
|
+
return server
|
1412
|
+
end
|
1413
|
+
module_function :current_server
|
1414
|
+
|
1415
|
+
def stop_service
|
1416
|
+
@primary_server.stop_service if @primary_server
|
1417
|
+
@primary_server = nil
|
1418
|
+
end
|
1419
|
+
module_function :stop_service
|
1420
|
+
|
1421
|
+
def uri
|
1422
|
+
drab = Thread.current['DRab']
|
1423
|
+
client = (drab && drab['client'])
|
1424
|
+
if client
|
1425
|
+
uri = client.uri
|
1426
|
+
return uri if uri
|
1427
|
+
end
|
1428
|
+
current_server.uri
|
1429
|
+
end
|
1430
|
+
module_function :uri
|
1431
|
+
|
1432
|
+
def here?(uri)
|
1433
|
+
current_server.here?(uri) rescue false
|
1434
|
+
# (current_server.uri rescue nil) == uri
|
1435
|
+
end
|
1436
|
+
module_function :here?
|
1437
|
+
|
1438
|
+
def config
|
1439
|
+
current_server.config
|
1440
|
+
rescue
|
1441
|
+
DRabServer.make_config
|
1442
|
+
end
|
1443
|
+
module_function :config
|
1444
|
+
|
1445
|
+
def front
|
1446
|
+
current_server.front
|
1447
|
+
end
|
1448
|
+
module_function :front
|
1449
|
+
|
1450
|
+
def to_obj(ref)
|
1451
|
+
current_server.to_obj(ref)
|
1452
|
+
end
|
1453
|
+
|
1454
|
+
def to_id(obj)
|
1455
|
+
current_server.to_id(obj)
|
1456
|
+
end
|
1457
|
+
module_function :to_id
|
1458
|
+
module_function :to_obj
|
1459
|
+
|
1460
|
+
def thread
|
1461
|
+
@primary_server ? @primary_server.thread : nil
|
1462
|
+
end
|
1463
|
+
module_function :thread
|
1464
|
+
|
1465
|
+
def install_acl(acl)
|
1466
|
+
DRabServer.default_acl(acl)
|
1467
|
+
end
|
1468
|
+
module_function :install_acl
|
1469
|
+
|
1470
|
+
#@mutex = Thread::Mutex.new
|
1471
|
+
@mutex = Mutex.new
|
1472
|
+
def mutex
|
1473
|
+
@mutex
|
1474
|
+
end
|
1475
|
+
module_function :mutex
|
1476
|
+
|
1477
|
+
@server = {}
|
1478
|
+
def regist_server(server)
|
1479
|
+
@server[server.uri] = server
|
1480
|
+
mutex.synchronize do
|
1481
|
+
@primary_server = server unless @primary_server
|
1482
|
+
end
|
1483
|
+
end
|
1484
|
+
module_function :regist_server
|
1485
|
+
|
1486
|
+
def remove_server(server)
|
1487
|
+
@server.delete(server.uri)
|
1488
|
+
end
|
1489
|
+
module_function :remove_server
|
1490
|
+
|
1491
|
+
def fetch_server(uri)
|
1492
|
+
@server[uri]
|
1493
|
+
end
|
1494
|
+
module_function :fetch_server
|
1495
|
+
end
|
1496
|
+
|
1497
|
+
DRabObject = DRab::DRabObject
|
1498
|
+
DRabUndumped = DRab::DRabUndumped
|
1499
|
+
DRabIdConv = DRab::DRabIdConv
|