jason-o-matic-drbfire 0.1.0

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