ntalbott-drbfire 0.1.2
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.
- data/ChangeLog +101 -0
- data/INSTALL +10 -0
- data/README +48 -0
- data/drbfire.gemspec +33 -0
- data/lib/drb/drbfire.rb +289 -0
- data/sample/client.rb +42 -0
- data/sample/server.rb +46 -0
- data/setup.rb +1306 -0
- data/test/test_drbfire.rb +138 -0
- metadata +66 -0
data/ChangeLog
ADDED
@@ -0,0 +1,101 @@
|
|
1
|
+
Wed Feb 25 20:56:11 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
2
|
+
|
3
|
+
* Release 0.1.0. Really.
|
4
|
+
|
5
|
+
* lib/drb/drbfire.rb: Updated the version number. Also added a few
|
6
|
+
nodoc directives.
|
7
|
+
|
8
|
+
Wed Feb 25 20:05:10 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
9
|
+
|
10
|
+
* Release 0.1.0.
|
11
|
+
|
12
|
+
* lib/drb/drbfire.rb: Simplified to only use one port.
|
13
|
+
|
14
|
+
* test/test_drbfire.rb: Removed obsolete tests related to the above
|
15
|
+
change.
|
16
|
+
|
17
|
+
* lib/drb/drbfire.rb: Added id wrapping and one server per process
|
18
|
+
caveats to the documentation.
|
19
|
+
|
20
|
+
Sun Jan 18 22:24:10 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
21
|
+
|
22
|
+
* Release 0.0.7.
|
23
|
+
|
24
|
+
* lib/drb/drbfire.rb: forgot to require timeout.
|
25
|
+
|
26
|
+
Sun Jan 18 22:09:51 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
27
|
+
|
28
|
+
* Release 0.0.6.
|
29
|
+
|
30
|
+
Sun Jan 18 22:00:44 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
31
|
+
|
32
|
+
* lib/drb/drbfire.rb: ignored connections with invalid client ids.
|
33
|
+
|
34
|
+
* *: added copyright notices.
|
35
|
+
|
36
|
+
* lib/drb/drbfire.rb: added RDoc.
|
37
|
+
|
38
|
+
* README: added.
|
39
|
+
|
40
|
+
* INSTALL: added.
|
41
|
+
|
42
|
+
Sat Jan 17 13:03:27 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
43
|
+
|
44
|
+
* lib/drb/drbfire.rb: increased robustness when accepting connections.
|
45
|
+
|
46
|
+
* lib/drb/drbfire.rb: fixed a race condition when accepting signal
|
47
|
+
connections.
|
48
|
+
|
49
|
+
* test/test_drbfire.rb: use the packet format constant.
|
50
|
+
|
51
|
+
* lib/drb/drbfire.rb: added a VERSION constant.
|
52
|
+
|
53
|
+
* Release 0.0.5.
|
54
|
+
|
55
|
+
Fri Jan 16 14:34:52 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
56
|
+
|
57
|
+
* Release 0.0.4.
|
58
|
+
|
59
|
+
Fri Jan 16 14:30:13 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
60
|
+
|
61
|
+
* test/test_drbfire.rb: improved the overall communication tests to
|
62
|
+
include client-side callbacks.
|
63
|
+
|
64
|
+
* lib/drb/drbfire.rb: fixed a bug with client-side callbacks caused by
|
65
|
+
improperly reporting the uri.
|
66
|
+
|
67
|
+
* samples/*.rb: improved the samples to include client-side callbacks.
|
68
|
+
|
69
|
+
Fri Jan 16 11:32:40 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
70
|
+
|
71
|
+
* Release 0.0.3.
|
72
|
+
|
73
|
+
Fri Jan 16 11:30:58 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
74
|
+
|
75
|
+
* lib/drb/drbfire.rb: added debugging code.
|
76
|
+
|
77
|
+
Fri Jan 16 11:11:02 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
78
|
+
|
79
|
+
* samples/server.rb: improved argument handling and added the ability
|
80
|
+
to specify the use of ssl.
|
81
|
+
|
82
|
+
* samples/client.rb: ditto.
|
83
|
+
|
84
|
+
* lib/drb/drbfire.rb: removed old debugging code.
|
85
|
+
|
86
|
+
Fri Jan 16 10:41:53 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
87
|
+
|
88
|
+
* samples/server.rb: added the ability to specify the host on the
|
89
|
+
commandline.
|
90
|
+
|
91
|
+
* samples/client.rb: ditto.
|
92
|
+
|
93
|
+
Thu Jan 15 21:01:02 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
94
|
+
|
95
|
+
* Release 0.0.2.
|
96
|
+
|
97
|
+
Thu Jan 15 20:59:08 2004 Nathaniel Talbott <nathaniel@talbott.ws>
|
98
|
+
|
99
|
+
* Changed how client id's are packed.
|
100
|
+
|
101
|
+
vim: set noexpandtab
|
data/INSTALL
ADDED
data/README
ADDED
@@ -0,0 +1,48 @@
|
|
1
|
+
= DRbFire
|
2
|
+
|
3
|
+
The DRb Firewall Protocol, or DRbFire, is a DRb protocol that allows
|
4
|
+
easy bidirectional communication in the presence of a firewall.
|
5
|
+
|
6
|
+
|
7
|
+
== Usage
|
8
|
+
|
9
|
+
DRbFire's usage is documented in the source using RDoc.
|
10
|
+
|
11
|
+
|
12
|
+
== Installation
|
13
|
+
|
14
|
+
See the INSTALL file.
|
15
|
+
|
16
|
+
|
17
|
+
== History
|
18
|
+
|
19
|
+
See the ChangeLog file.
|
20
|
+
|
21
|
+
|
22
|
+
== Feedback
|
23
|
+
|
24
|
+
Feedback of any kind is welcome; you can contact me (Nathaniel
|
25
|
+
Talbott) at drbfire@talbott.ws.
|
26
|
+
|
27
|
+
|
28
|
+
== More Information
|
29
|
+
|
30
|
+
DRbFire's home is at http://rubyforge.org/projects/drbfire.
|
31
|
+
|
32
|
+
|
33
|
+
== Copyright
|
34
|
+
|
35
|
+
Copyright (c) 2004 Nathaniel Talbott. All Rights Reserved.
|
36
|
+
|
37
|
+
|
38
|
+
== License
|
39
|
+
|
40
|
+
DRbFire is free software distributed under the Ruby license. See the
|
41
|
+
COPYING file in the standard Ruby distribution for details.
|
42
|
+
|
43
|
+
|
44
|
+
== Warranty
|
45
|
+
|
46
|
+
This software is provided "as is" and without any express or implied
|
47
|
+
warranties, including, without limitation, the implied warranties of
|
48
|
+
merchantibility and fitness for a particular purpose.
|
data/drbfire.gemspec
ADDED
@@ -0,0 +1,33 @@
|
|
1
|
+
# -*- encoding: utf-8 -*-
|
2
|
+
|
3
|
+
Gem::Specification.new do |s|
|
4
|
+
s.name = %q{drbfire}
|
5
|
+
s.version = "0.1.2"
|
6
|
+
|
7
|
+
s.required_rubygems_version = Gem::Requirement.new(">= 0") if s.respond_to? :required_rubygems_version=
|
8
|
+
s.authors = ["Nathaniel Talbott"]
|
9
|
+
s.date = %q{2009-02-07}
|
10
|
+
# s.default_executable = %q{deep_test}
|
11
|
+
s.description = %q{DRbFire allows easy bidirectional DRb communication in the presence of a firewall.}
|
12
|
+
s.email = %q{drbfire@talbott.ws}
|
13
|
+
# s.executables = ["deep_test"]
|
14
|
+
s.extra_rdoc_files = ["README", "ChangeLog"]
|
15
|
+
s.files = ["ChangeLog", "drbfire.gemspec", "INSTALL", "lib/drb/drbfire.rb", "README", "sample/client.rb", "sample/server.rb", "setup.rb", "test/test_drbfire.rb"]
|
16
|
+
s.has_rdoc = true
|
17
|
+
s.homepage = %q{http://rubyforge.org/projects/drbfire}
|
18
|
+
s.rdoc_options = ["--title", "DRbFire", "--main", "README", "--line-numbers"]
|
19
|
+
s.require_paths = ["lib"]
|
20
|
+
s.rubyforge_project = %q{drbfire}
|
21
|
+
s.rubygems_version = %q{1.3.0}
|
22
|
+
s.summary = %q{DRbFire allows easy bidirectional DRb communication in the presence of a firewall.}
|
23
|
+
|
24
|
+
if s.respond_to? :specification_version then
|
25
|
+
current_version = Gem::Specification::CURRENT_SPECIFICATION_VERSION
|
26
|
+
s.specification_version = 2
|
27
|
+
|
28
|
+
if Gem::Version.new(Gem::RubyGemsVersion) >= Gem::Version.new('1.2.0') then
|
29
|
+
else
|
30
|
+
end
|
31
|
+
else
|
32
|
+
end
|
33
|
+
end
|
data/lib/drb/drbfire.rb
ADDED
@@ -0,0 +1,289 @@
|
|
1
|
+
# :include:README
|
2
|
+
#--
|
3
|
+
# Author:: Nathaniel Talbott.
|
4
|
+
# Copyright:: Copyright (c) 2004 Nathaniel Talbott. All rights reserved.
|
5
|
+
# License:: Ruby license.
|
6
|
+
|
7
|
+
require 'delegate'
|
8
|
+
require 'drb'
|
9
|
+
require 'timeout'
|
10
|
+
|
11
|
+
# = DRb Firewall Protocol
|
12
|
+
#
|
13
|
+
# == Prerequisites
|
14
|
+
#
|
15
|
+
# It is assumed that you already know how to use DRb; if you don't
|
16
|
+
# you'll need to go read up on it and understand the basics of how it
|
17
|
+
# works before using DRbFire. DRbFire actually wraps the standard
|
18
|
+
# protocols that DRb uses, so generally anything that applies to them
|
19
|
+
# applies to DRbFire.
|
20
|
+
#
|
21
|
+
#
|
22
|
+
# == Basic Usage
|
23
|
+
#
|
24
|
+
# Using DRbFire is quite simple, and can be summed up in four steps:
|
25
|
+
#
|
26
|
+
# 1. Start with <tt>require 'drb/drbfire'</tt>.
|
27
|
+
#
|
28
|
+
# 2. Use <tt>drbfire://</tt> instead of <tt>druby://</tt> when
|
29
|
+
# specifying the server url.
|
30
|
+
#
|
31
|
+
# 3. When calling <tt>DRb.start_service</tt> on the client, specify
|
32
|
+
# the server's uri as the uri (as opposed to the normal usage, which
|
33
|
+
# is to specify *no* uri).
|
34
|
+
#
|
35
|
+
# 4. Specify the right configuration when calling
|
36
|
+
# <tt>DRb.start_service</tt>, specifically the role to use:
|
37
|
+
# On the server:: <tt>DRbFire::ROLE => DRbFire::SERVER</tt>
|
38
|
+
# On the client:: <tt>DRbFire::ROLE => DRbFire::CLIENT</tt>
|
39
|
+
#
|
40
|
+
# So a simple server would look like:
|
41
|
+
#
|
42
|
+
# require 'drb/drbfire'
|
43
|
+
#
|
44
|
+
# front = ['a', 'b', 'c']
|
45
|
+
# DRb.start_service('drbfire://some.server.com:5555', front, DRbFire::ROLE => DRbFire::SERVER)
|
46
|
+
# DRb.thread.join
|
47
|
+
#
|
48
|
+
# And a simple client:
|
49
|
+
#
|
50
|
+
# require 'drb/drbfire'
|
51
|
+
#
|
52
|
+
# DRb.start_service('drbfire://some.server.com:5555', nil, DRbFire::ROLE => DRbFire::CLIENT)
|
53
|
+
# DRbObject.new(nil, 'drbfire://some.server.com:5555').each do |e|
|
54
|
+
# p e
|
55
|
+
# end
|
56
|
+
#
|
57
|
+
#
|
58
|
+
# == Advanced Usage
|
59
|
+
#
|
60
|
+
# You can do some more interesting tricks with DRbFire, too:
|
61
|
+
#
|
62
|
+
# <b>Using SSL</b>:: To do this, you have to set the delegate in the
|
63
|
+
# configuration (on both the server and the client) using
|
64
|
+
# <tt>DRbFire::DELEGATE => DRb::DRbSSLSocket</tt>. Other
|
65
|
+
# DRb protcols may also work as delegates, but only the
|
66
|
+
# SSL protocol is tested.
|
67
|
+
#
|
68
|
+
#
|
69
|
+
# == Caveats
|
70
|
+
#
|
71
|
+
# * DRbFire uses a 32-bit id space, meaning ids will wrap after
|
72
|
+
# approximately ~4.2 billion connections. If that's a non-theoretical
|
73
|
+
# problem for you, and you tell me about it, I'll figure out some
|
74
|
+
# way to fix it. It'd be worth it just to find out that DRbFire is
|
75
|
+
# being used in such a mind-blowing fashion.
|
76
|
+
#
|
77
|
+
# * You're limited to one _server_ per process at this point. You can
|
78
|
+
# have (and handle) as many clients as you want (well, ok, so I just
|
79
|
+
# said there's really a limit somewhere around 4.2 billion. I'm
|
80
|
+
# trying to simplify here). Again, this is possible to deal with,
|
81
|
+
# but not something that I've needed at this point and not something
|
82
|
+
# I'm guessing is terribly common. Let me know if it's a problem for
|
83
|
+
# you.
|
84
|
+
|
85
|
+
|
86
|
+
module DRbFire
|
87
|
+
# The current version.
|
88
|
+
VERSION = [0, 1, 0]
|
89
|
+
|
90
|
+
# The role configuration key.
|
91
|
+
ROLE = "#{self}::ROLE"
|
92
|
+
|
93
|
+
# The server role configuration value.
|
94
|
+
SERVER = "#{self}::SERVER"
|
95
|
+
|
96
|
+
# The client role configuration value.
|
97
|
+
CLIENT = "#{self}::CLIENT"
|
98
|
+
|
99
|
+
# The delegate configuration key.
|
100
|
+
DELEGATE = "#{self}::DELEGATE"
|
101
|
+
|
102
|
+
# Miscellaneous constants
|
103
|
+
SCHEME = "drbfire" #:nodoc:
|
104
|
+
ID_FORMAT = "N" #:nodoc:
|
105
|
+
INCOMING_CONN = "1" #:nodoc:
|
106
|
+
OUTGOING_CONN = "2" #:nodoc:
|
107
|
+
SIGNAL_CONN = "3" #:nodoc:
|
108
|
+
|
109
|
+
class Protocol < SimpleDelegator #nodoc:all
|
110
|
+
class ClientServer
|
111
|
+
attr_reader :signal_id
|
112
|
+
|
113
|
+
def initialize(uri, config)
|
114
|
+
@uri = uri
|
115
|
+
@config = config
|
116
|
+
@connection = Protocol.open(uri, config, SIGNAL_CONN)
|
117
|
+
@signal_id = @connection.read_signal_id
|
118
|
+
end
|
119
|
+
|
120
|
+
def uri
|
121
|
+
"#{@uri}?#{@signal_id}"
|
122
|
+
end
|
123
|
+
|
124
|
+
def accept
|
125
|
+
@connection.stream.read(1)
|
126
|
+
connection = Protocol.open(@uri, @config, OUTGOING_CONN)
|
127
|
+
connection.stream.write([@signal_id].pack(ID_FORMAT))
|
128
|
+
connection
|
129
|
+
end
|
130
|
+
|
131
|
+
def close
|
132
|
+
@connection.close
|
133
|
+
end
|
134
|
+
end
|
135
|
+
|
136
|
+
class ClientServerProxy
|
137
|
+
def initialize(connection, id)
|
138
|
+
@connection = connection
|
139
|
+
@id = id
|
140
|
+
@queue = Queue.new
|
141
|
+
end
|
142
|
+
|
143
|
+
def write_signal_id
|
144
|
+
@connection.stream.write([@id].pack(ID_FORMAT))
|
145
|
+
end
|
146
|
+
|
147
|
+
def push(connection)
|
148
|
+
@queue.push(connection)
|
149
|
+
end
|
150
|
+
|
151
|
+
def open
|
152
|
+
@connection.stream.write("0")
|
153
|
+
timeout(20) do
|
154
|
+
@queue.pop
|
155
|
+
end
|
156
|
+
rescue TimeoutError
|
157
|
+
raise DRb::DRbConnError, "Unable to get a client connection."
|
158
|
+
end
|
159
|
+
end
|
160
|
+
|
161
|
+
class << self
|
162
|
+
def open_server(uri, config)
|
163
|
+
if(server?(config))
|
164
|
+
@client_servers ||= {}
|
165
|
+
|
166
|
+
sock = delegate(config).open_server(uri, config)
|
167
|
+
|
168
|
+
# get the uri from the delegate, and replace the scheme with drbfire://
|
169
|
+
# this allows randomly chosen ports (:0) to work
|
170
|
+
scheme = sock.uri.match(/^(.*):\/\//)[1]
|
171
|
+
drbfire_uri = sock.uri.sub(scheme, SCHEME)
|
172
|
+
|
173
|
+
new(drbfire_uri, sock)
|
174
|
+
else
|
175
|
+
ClientServer.new(uri, config)
|
176
|
+
end
|
177
|
+
end
|
178
|
+
|
179
|
+
def open(uri, config, type=INCOMING_CONN)
|
180
|
+
unless(server?(config))
|
181
|
+
connection = new(uri, delegate(config).open(uri, config))
|
182
|
+
connection.stream.write(type)
|
183
|
+
connection
|
184
|
+
else
|
185
|
+
@client_servers[parse_uri(uri).last.to_i].open
|
186
|
+
end
|
187
|
+
end
|
188
|
+
|
189
|
+
def add_client_connection(id, connection)
|
190
|
+
if((c = @client_servers[id]))
|
191
|
+
c.push(connection)
|
192
|
+
else
|
193
|
+
end
|
194
|
+
end
|
195
|
+
|
196
|
+
def add_client_server(id, server)
|
197
|
+
@client_servers[id] = server
|
198
|
+
end
|
199
|
+
|
200
|
+
def parse_uri(uri)
|
201
|
+
if(%r{^#{SCHEME}://([^:]+):(\d+)(?:\?(.+))?$} =~ uri)
|
202
|
+
[$1, $2.to_i, $3]
|
203
|
+
else
|
204
|
+
raise DRb::DRbBadScheme, uri unless(/^#{SCHEME}/ =~ uri)
|
205
|
+
raise DRb::DRbBadURI, "Can't parse uri: #{uri}"
|
206
|
+
end
|
207
|
+
end
|
208
|
+
|
209
|
+
def uri_option(uri, config)
|
210
|
+
host, port, option = parse_uri(uri)
|
211
|
+
return "#{SCHEME}://#{host}:#{port}", option
|
212
|
+
end
|
213
|
+
|
214
|
+
private
|
215
|
+
|
216
|
+
def server?(config)
|
217
|
+
raise "Invalid configuration" unless(config.include?(ROLE))
|
218
|
+
config[ROLE] == SERVER
|
219
|
+
end
|
220
|
+
|
221
|
+
def delegate(config)
|
222
|
+
unless(defined?(@delegate))
|
223
|
+
@delegate = Class.new(config[DELEGATE] || DRb::DRbTCPSocket) do
|
224
|
+
class << self
|
225
|
+
attr_writer :delegate
|
226
|
+
|
227
|
+
def parse_uri(uri)
|
228
|
+
@delegate.parse_uri(uri)
|
229
|
+
end
|
230
|
+
|
231
|
+
def uri_option(uri, config)
|
232
|
+
@delegate.uri_option(uri, config)
|
233
|
+
end
|
234
|
+
end
|
235
|
+
end
|
236
|
+
@delegate.delegate = self
|
237
|
+
end
|
238
|
+
@delegate
|
239
|
+
end
|
240
|
+
end
|
241
|
+
|
242
|
+
attr_reader :signal_id, :uri
|
243
|
+
|
244
|
+
def initialize(uri, delegate)
|
245
|
+
super(delegate)
|
246
|
+
@uri = uri
|
247
|
+
@id = 0
|
248
|
+
@id_mutex = Mutex.new
|
249
|
+
end
|
250
|
+
|
251
|
+
def accept
|
252
|
+
while(__getobj__.instance_eval{@socket})
|
253
|
+
begin
|
254
|
+
connection = self.class.new(nil, __getobj__.accept)
|
255
|
+
rescue IOError
|
256
|
+
return nil
|
257
|
+
end
|
258
|
+
begin
|
259
|
+
type = connection.stream.read(1)
|
260
|
+
rescue
|
261
|
+
next
|
262
|
+
end
|
263
|
+
case type
|
264
|
+
when INCOMING_CONN
|
265
|
+
return connection
|
266
|
+
when OUTGOING_CONN
|
267
|
+
self.class.add_client_connection(connection.read_signal_id, connection)
|
268
|
+
next
|
269
|
+
when SIGNAL_CONN
|
270
|
+
new_id = nil
|
271
|
+
@id_mutex.synchronize do
|
272
|
+
new_id = (@id += 1)
|
273
|
+
end
|
274
|
+
client_server = ClientServerProxy.new(connection, new_id)
|
275
|
+
self.class.add_client_server(new_id, client_server)
|
276
|
+
client_server.write_signal_id
|
277
|
+
next
|
278
|
+
else
|
279
|
+
raise "Invalid type #{type}"
|
280
|
+
end
|
281
|
+
end
|
282
|
+
end
|
283
|
+
|
284
|
+
def read_signal_id
|
285
|
+
stream.read(4).unpack(ID_FORMAT).first
|
286
|
+
end
|
287
|
+
end
|
288
|
+
end
|
289
|
+
DRb::DRbProtocol.add_protocol(DRbFire::Protocol)
|