jason-o-matic-drbfire 0.1.0

This diff represents the content of publicly available package versions that have been released to one of the supported registries. The information contained in this diff is provided for informational purposes only and reflects changes between package versions as they appear in their respective public registries.
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
@@ -0,0 +1,10 @@
1
+ From the root of the package, run:
2
+
3
+ ruby setup.rb config
4
+ ruby setup.rb setup
5
+ ruby setup.rb install
6
+
7
+ Further install options are available using:
8
+
9
+ ruby setup.rb --help
10
+
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.0"
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
@@ -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)