PageRenderTime 51ms CodeModel.GetById 17ms RepoModel.GetById 1ms app.codeStats 0ms

/Util/IronRuby/lib/ruby/1.8/drb/drb.rb

http://github.com/IronLanguages/main
Ruby | 1764 lines | 925 code | 137 blank | 702 comment | 75 complexity | 13b257085708c384e6a66a1fe4984519 MD5 | raw file
Possible License(s): CPL-1.0, BSD-3-Clause, ISC, GPL-2.0, MPL-2.0-no-copyleft-exception

Large files files are truncated, but you can click here to view the full file

  1. #
  2. # = drb/drb.rb
  3. #
  4. # Distributed Ruby: _dRuby_ version 2.0.4
  5. #
  6. # Copyright (c) 1999-2003 Masatoshi SEKI. You can redistribute it and/or
  7. # modify it under the same terms as Ruby.
  8. #
  9. # Author:: Masatoshi SEKI
  10. #
  11. # Documentation:: William Webber (william@williamwebber.com)
  12. #
  13. # == Overview
  14. #
  15. # dRuby is a distributed object system for Ruby. It allows an object in one
  16. # Ruby process to invoke methods on an object in another Ruby process on the
  17. # same or a different machine.
  18. #
  19. # The Ruby standard library contains the core classes of the dRuby package.
  20. # However, the full package also includes access control lists and the
  21. # Rinda tuple-space distributed task management system, as well as a
  22. # large number of samples. The full dRuby package can be downloaded from
  23. # the dRuby home page (see *References*).
  24. #
  25. # For an introduction and examples of usage see the documentation to the
  26. # DRb module.
  27. #
  28. # == References
  29. #
  30. # [http://www2a.biglobe.ne.jp/~seki/ruby/druby.html]
  31. # The dRuby home page, in Japanese. Contains the full dRuby package
  32. # and links to other Japanese-language sources.
  33. #
  34. # [http://www2a.biglobe.ne.jp/~seki/ruby/druby.en.html]
  35. # The English version of the dRuby home page.
  36. #
  37. # [http://www.chadfowler.com/ruby/drb.html]
  38. # A quick tutorial introduction to using dRuby by Chad Fowler.
  39. #
  40. # [http://www.linux-mag.com/2002-09/ruby_05.html]
  41. # A tutorial introduction to dRuby in Linux Magazine by Dave Thomas.
  42. # Includes a discussion of Rinda.
  43. #
  44. # [http://www.eng.cse.dmu.ac.uk/~hgs/ruby/dRuby/]
  45. # Links to English-language Ruby material collected by Hugh Sasse.
  46. #
  47. # [http://www.rubycentral.com/book/ospace.html]
  48. # The chapter from *Programming* *Ruby* by Dave Thomas and Andy Hunt
  49. # which discusses dRuby.
  50. #
  51. # [http://www.clio.ne.jp/home/web-i31s/Flotuard/Ruby/PRC2K_seki/dRuby.en.html]
  52. # Translation of presentation on Ruby by Masatoshi Seki.
  53. require 'socket'
  54. require 'thread'
  55. require 'fcntl'
  56. require 'drb/eq'
  57. #
  58. # == Overview
  59. #
  60. # dRuby is a distributed object system for Ruby. It is written in
  61. # pure Ruby and uses its own protocol. No add-in services are needed
  62. # beyond those provided by the Ruby runtime, such as TCP sockets. It
  63. # does not rely on or interoperate with other distributed object
  64. # systems such as CORBA, RMI, or .NET.
  65. #
  66. # dRuby allows methods to be called in one Ruby process upon a Ruby
  67. # object located in another Ruby process, even on another machine.
  68. # References to objects can be passed between processes. Method
  69. # arguments and return values are dumped and loaded in marshalled
  70. # format. All of this is done transparently to both the caller of the
  71. # remote method and the object that it is called upon.
  72. #
  73. # An object in a remote process is locally represented by a
  74. # DRb::DRbObject instance. This acts as a sort of proxy for the
  75. # remote object. Methods called upon this DRbObject instance are
  76. # forwarded to its remote object. This is arranged dynamically at run
  77. # time. There are no statically declared interfaces for remote
  78. # objects, such as CORBA's IDL.
  79. #
  80. # dRuby calls made into a process are handled by a DRb::DRbServer
  81. # instance within that process. This reconstitutes the method call,
  82. # invokes it upon the specified local object, and returns the value to
  83. # the remote caller. Any object can receive calls over dRuby. There
  84. # is no need to implement a special interface, or mixin special
  85. # functionality. Nor, in the general case, does an object need to
  86. # explicitly register itself with a DRbServer in order to receive
  87. # dRuby calls.
  88. #
  89. # One process wishing to make dRuby calls upon another process must
  90. # somehow obtain an initial reference to an object in the remote
  91. # process by some means other than as the return value of a remote
  92. # method call, as there is initially no remote object reference it can
  93. # invoke a method upon. This is done by attaching to the server by
  94. # URI. Each DRbServer binds itself to a URI such as
  95. # 'druby://example.com:8787'. A DRbServer can have an object attached
  96. # to it that acts as the server's *front* *object*. A DRbObject can
  97. # be explicitly created from the server's URI. This DRbObject's
  98. # remote object will be the server's front object. This front object
  99. # can then return references to other Ruby objects in the DRbServer's
  100. # process.
  101. #
  102. # Method calls made over dRuby behave largely the same as normal Ruby
  103. # method calls made within a process. Method calls with blocks are
  104. # supported, as are raising exceptions. In addition to a method's
  105. # standard errors, a dRuby call may also raise one of the
  106. # dRuby-specific errors, all of which are subclasses of DRb::DRbError.
  107. #
  108. # Any type of object can be passed as an argument to a dRuby call or
  109. # returned as its return value. By default, such objects are dumped
  110. # or marshalled at the local end, then loaded or unmarshalled at the
  111. # remote end. The remote end therefore receives a copy of the local
  112. # object, not a distributed reference to it; methods invoked upon this
  113. # copy are executed entirely in the remote process, not passed on to
  114. # the local original. This has semantics similar to pass-by-value.
  115. #
  116. # However, if an object cannot be marshalled, a dRuby reference to it
  117. # is passed or returned instead. This will turn up at the remote end
  118. # as a DRbObject instance. All methods invoked upon this remote proxy
  119. # are forwarded to the local object, as described in the discussion of
  120. # DRbObjects. This has semantics similar to the normal Ruby
  121. # pass-by-reference.
  122. #
  123. # The easiest way to signal that we want an otherwise marshallable
  124. # object to be passed or returned as a DRbObject reference, rather
  125. # than marshalled and sent as a copy, is to include the
  126. # DRb::DRbUndumped mixin module.
  127. #
  128. # dRuby supports calling remote methods with blocks. As blocks (or
  129. # rather the Proc objects that represent them) are not marshallable,
  130. # the block executes in the local, not the remote, context. Each
  131. # value yielded to the block is passed from the remote object to the
  132. # local block, then the value returned by each block invocation is
  133. # passed back to the remote execution context to be collected, before
  134. # the collected values are finally returned to the local context as
  135. # the return value of the method invocation.
  136. #
  137. # == Examples of usage
  138. #
  139. # For more dRuby samples, see the +samples+ directory in the full
  140. # dRuby distribution.
  141. #
  142. # === dRuby in client/server mode
  143. #
  144. # This illustrates setting up a simple client-server drb
  145. # system. Run the server and client code in different terminals,
  146. # starting the server code first.
  147. #
  148. # ==== Server code
  149. #
  150. # require 'drb/drb'
  151. #
  152. # # The URI for the server to connect to
  153. # URI="druby://localhost:8787"
  154. #
  155. # class TimeServer
  156. #
  157. # def get_current_time
  158. # return Time.now
  159. # end
  160. #
  161. # end
  162. #
  163. # # The object that handles requests on the server
  164. # FRONT_OBJECT=TimeServer.new
  165. #
  166. # $SAFE = 1 # disable eval() and friends
  167. #
  168. # DRb.start_service(URI, FRONT_OBJECT)
  169. # # Wait for the drb server thread to finish before exiting.
  170. # DRb.thread.join
  171. #
  172. # ==== Client code
  173. #
  174. # require 'drb/drb'
  175. #
  176. # # The URI to connect to
  177. # SERVER_URI="druby://localhost:8787"
  178. #
  179. # # Start a local DRbServer to handle callbacks.
  180. # #
  181. # # Not necessary for this small example, but will be required
  182. # # as soon as we pass a non-marshallable object as an argument
  183. # # to a dRuby call.
  184. # DRb.start_service
  185. #
  186. # timeserver = DRbObject.new_with_uri(SERVER_URI)
  187. # puts timeserver.get_current_time
  188. #
  189. # === Remote objects under dRuby
  190. #
  191. # This example illustrates returning a reference to an object
  192. # from a dRuby call. The Logger instances live in the server
  193. # process. References to them are returned to the client process,
  194. # where methods can be invoked upon them. These methods are
  195. # executed in the server process.
  196. #
  197. # ==== Server code
  198. #
  199. # require 'drb/drb'
  200. #
  201. # URI="druby://localhost:8787"
  202. #
  203. # class Logger
  204. #
  205. # # Make dRuby send Logger instances as dRuby references,
  206. # # not copies.
  207. # include DRb::DRbUndumped
  208. #
  209. # def initialize(n, fname)
  210. # @name = n
  211. # @filename = fname
  212. # end
  213. #
  214. # def log(message)
  215. # File.open(@filename, "a") do |f|
  216. # f.puts("#{Time.now}: #{@name}: #{message}")
  217. # end
  218. # end
  219. #
  220. # end
  221. #
  222. # # We have a central object for creating and retrieving loggers.
  223. # # This retains a local reference to all loggers created. This
  224. # # is so an existing logger can be looked up by name, but also
  225. # # to prevent loggers from being garbage collected. A dRuby
  226. # # reference to an object is not sufficient to prevent it being
  227. # # garbage collected!
  228. # class LoggerFactory
  229. #
  230. # def initialize(bdir)
  231. # @basedir = bdir
  232. # @loggers = {}
  233. # end
  234. #
  235. # def get_logger(name)
  236. # if !@loggers.has_key? name
  237. # # make the filename safe, then declare it to be so
  238. # fname = name.gsub(/[.\/]/, "_").untaint
  239. # @loggers[name] = Logger.new(name, @basedir + "/" + fname)
  240. # end
  241. # return @loggers[name]
  242. # end
  243. #
  244. # end
  245. #
  246. # FRONT_OBJECT=LoggerFactory.new("/tmp/dlog")
  247. #
  248. # $SAFE = 1 # disable eval() and friends
  249. #
  250. # DRb.start_service(URI, FRONT_OBJECT)
  251. # DRb.thread.join
  252. #
  253. # ==== Client code
  254. #
  255. # require 'drb/drb'
  256. #
  257. # SERVER_URI="druby://localhost:8787"
  258. #
  259. # DRb.start_service
  260. #
  261. # log_service=DRbObject.new_with_uri(SERVER_URI)
  262. #
  263. # ["loga", "logb", "logc"].each do |logname|
  264. #
  265. # logger=log_service.get_logger(logname)
  266. #
  267. # logger.log("Hello, world!")
  268. # logger.log("Goodbye, world!")
  269. # logger.log("=== EOT ===")
  270. #
  271. # end
  272. #
  273. # == Security
  274. #
  275. # As with all network services, security needs to be considered when
  276. # using dRuby. By allowing external access to a Ruby object, you are
  277. # not only allowing outside clients to call the methods you have
  278. # defined for that object, but by default to execute arbitrary Ruby
  279. # code on your server. Consider the following:
  280. #
  281. # # !!! UNSAFE CODE !!!
  282. # ro = DRbObject::new_with_uri("druby://your.server.com:8989")
  283. # class << ro
  284. # undef :instance_eval # force call to be passed to remote object
  285. # end
  286. # ro.instance_eval("`rm -rf *`")
  287. #
  288. # The dangers posed by instance_eval and friends are such that a
  289. # DRbServer should generally be run with $SAFE set to at least
  290. # level 1. This will disable eval() and related calls on strings
  291. # passed across the wire. The sample usage code given above follows
  292. # this practice.
  293. #
  294. # A DRbServer can be configured with an access control list to
  295. # selectively allow or deny access from specified IP addresses. The
  296. # main druby distribution provides the ACL class for this purpose. In
  297. # general, this mechanism should only be used alongside, rather than
  298. # as a replacement for, a good firewall.
  299. #
  300. # == dRuby internals
  301. #
  302. # dRuby is implemented using three main components: a remote method
  303. # call marshaller/unmarshaller; a transport protocol; and an
  304. # ID-to-object mapper. The latter two can be directly, and the first
  305. # indirectly, replaced, in order to provide different behaviour and
  306. # capabilities.
  307. #
  308. # Marshalling and unmarshalling of remote method calls is performed by
  309. # a DRb::DRbMessage instance. This uses the Marshal module to dump
  310. # the method call before sending it over the transport layer, then
  311. # reconstitute it at the other end. There is normally no need to
  312. # replace this component, and no direct way is provided to do so.
  313. # However, it is possible to implement an alternative marshalling
  314. # scheme as part of an implementation of the transport layer.
  315. #
  316. # The transport layer is responsible for opening client and server
  317. # network connections and forwarding dRuby request across them.
  318. # Normally, it uses DRb::DRbMessage internally to manage marshalling
  319. # and unmarshalling. The transport layer is managed by
  320. # DRb::DRbProtocol. Multiple protocols can be installed in
  321. # DRbProtocol at the one time; selection between them is determined by
  322. # the scheme of a dRuby URI. The default transport protocol is
  323. # selected by the scheme 'druby:', and implemented by
  324. # DRb::DRbTCPSocket. This uses plain TCP/IP sockets for
  325. # communication. An alternative protocol, using UNIX domain sockets,
  326. # is implemented by DRb::DRbUNIXSocket in the file drb/unix.rb, and
  327. # selected by the scheme 'drbunix:'. A sample implementation over
  328. # HTTP can be found in the samples accompanying the main dRuby
  329. # distribution.
  330. #
  331. # The ID-to-object mapping component maps dRuby object ids to the
  332. # objects they refer to, and vice versa. The implementation to use
  333. # can be specified as part of a DRb::DRbServer's configuration. The
  334. # default implementation is provided by DRb::DRbIdConv. It uses an
  335. # object's ObjectSpace id as its dRuby id. This means that the dRuby
  336. # reference to that object only remains meaningful for the lifetime of
  337. # the object's process and the lifetime of the object within that
  338. # process. A modified implementation is provided by DRb::TimerIdConv
  339. # in the file drb/timeridconv.rb. This implementation retains a local
  340. # reference to all objects exported over dRuby for a configurable
  341. # period of time (defaulting to ten minutes), to prevent them being
  342. # garbage-collected within this time. Another sample implementation
  343. # is provided in sample/name.rb in the main dRuby distribution. This
  344. # allows objects to specify their own id or "name". A dRuby reference
  345. # can be made persistent across processes by having each process
  346. # register an object using the same dRuby name.
  347. #
  348. module DRb
  349. # Superclass of all errors raised in the DRb module.
  350. class DRbError < RuntimeError; end
  351. # Error raised when an error occurs on the underlying communication
  352. # protocol.
  353. class DRbConnError < DRbError; end
  354. # Class responsible for converting between an object and its id.
  355. #
  356. # This, the default implementation, uses an object's local ObjectSpace
  357. # __id__ as its id. This means that an object's identification over
  358. # drb remains valid only while that object instance remains alive
  359. # within the server runtime.
  360. #
  361. # For alternative mechanisms, see DRb::TimerIdConv in rdb/timeridconv.rb
  362. # and DRbNameIdConv in sample/name.rb in the full drb distribution.
  363. class DRbIdConv
  364. # Convert an object reference id to an object.
  365. #
  366. # This implementation looks up the reference id in the local object
  367. # space and returns the object it refers to.
  368. def to_obj(ref)
  369. ObjectSpace._id2ref(ref)
  370. end
  371. # Convert an object into a reference id.
  372. #
  373. # This implementation returns the object's __id__ in the local
  374. # object space.
  375. def to_id(obj)
  376. obj.nil? ? nil : obj.__id__
  377. end
  378. end
  379. # Mixin module making an object undumpable or unmarshallable.
  380. #
  381. # If an object which includes this module is returned by method
  382. # called over drb, then the object remains in the server space
  383. # and a reference to the object is returned, rather than the
  384. # object being marshalled and moved into the client space.
  385. module DRbUndumped
  386. def _dump(dummy) # :nodoc:
  387. raise TypeError, 'can\'t dump'
  388. end
  389. end
  390. # Error raised by the DRb module when an attempt is made to refer to
  391. # the context's current drb server but the context does not have one.
  392. # See #current_server.
  393. class DRbServerNotFound < DRbError; end
  394. # Error raised by the DRbProtocol module when it cannot find any
  395. # protocol implementation support the scheme specified in a URI.
  396. class DRbBadURI < DRbError; end
  397. # Error raised by a dRuby protocol when it doesn't support the
  398. # scheme specified in a URI. See DRb::DRbProtocol.
  399. class DRbBadScheme < DRbError; end
  400. # An exception wrapping a DRb::DRbUnknown object
  401. class DRbUnknownError < DRbError
  402. # Create a new DRbUnknownError for the DRb::DRbUnknown object +unknown+
  403. def initialize(unknown)
  404. @unknown = unknown
  405. super(unknown.name)
  406. end
  407. # Get the wrapped DRb::DRbUnknown object.
  408. attr_reader :unknown
  409. def self._load(s) # :nodoc:
  410. Marshal::load(s)
  411. end
  412. def _dump(lv) # :nodoc:
  413. Marshal::dump(@unknown)
  414. end
  415. end
  416. # An exception wrapping an error object
  417. class DRbRemoteError < DRbError
  418. def initialize(error)
  419. @reason = error.class.to_s
  420. super("#{error.message} (#{error.class})")
  421. set_backtrace(error.backtrace)
  422. end
  423. # the class of the error, as a string.
  424. attr_reader :reason
  425. end
  426. # Class wrapping a marshalled object whose type is unknown locally.
  427. #
  428. # If an object is returned by a method invoked over drb, but the
  429. # class of the object is unknown in the client namespace, or
  430. # the object is a constant unknown in the client namespace, then
  431. # the still-marshalled object is returned wrapped in a DRbUnknown instance.
  432. #
  433. # If this object is passed as an argument to a method invoked over
  434. # drb, then the wrapped object is passed instead.
  435. #
  436. # The class or constant name of the object can be read from the
  437. # +name+ attribute. The marshalled object is held in the +buf+
  438. # attribute.
  439. class DRbUnknown
  440. # Create a new DRbUnknown object.
  441. #
  442. # +buf+ is a string containing a marshalled object that could not
  443. # be unmarshalled. +err+ is the error message that was raised
  444. # when the unmarshalling failed. It is used to determine the
  445. # name of the unmarshalled object.
  446. def initialize(err, buf)
  447. case err.to_s
  448. when /uninitialized constant (\S+)/
  449. @name = $1
  450. when /undefined class\/module (\S+)/
  451. @name = $1
  452. else
  453. @name = nil
  454. end
  455. @buf = buf
  456. end
  457. # The name of the unknown thing.
  458. #
  459. # Class name for unknown objects; variable name for unknown
  460. # constants.
  461. attr_reader :name
  462. # Buffer contained the marshalled, unknown object.
  463. attr_reader :buf
  464. def self._load(s) # :nodoc:
  465. begin
  466. Marshal::load(s)
  467. rescue NameError, ArgumentError
  468. DRbUnknown.new($!, s)
  469. end
  470. end
  471. def _dump(lv) # :nodoc:
  472. @buf
  473. end
  474. # Attempt to load the wrapped marshalled object again.
  475. #
  476. # If the class of the object is now known locally, the object
  477. # will be unmarshalled and returned. Otherwise, a new
  478. # but identical DRbUnknown object will be returned.
  479. def reload
  480. self.class._load(@buf)
  481. end
  482. # Create a DRbUnknownError exception containing this object.
  483. def exception
  484. DRbUnknownError.new(self)
  485. end
  486. end
  487. class DRbArray
  488. def initialize(ary)
  489. @ary = ary.collect { |obj|
  490. if obj.kind_of? DRbUndumped
  491. DRbObject.new(obj)
  492. else
  493. begin
  494. Marshal.dump(obj)
  495. obj
  496. rescue
  497. DRbObject.new(obj)
  498. end
  499. end
  500. }
  501. end
  502. def self._load(s)
  503. Marshal::load(s)
  504. end
  505. def _dump(lv)
  506. Marshal.dump(@ary)
  507. end
  508. end
  509. # Handler for sending and receiving drb messages.
  510. #
  511. # This takes care of the low-level marshalling and unmarshalling
  512. # of drb requests and responses sent over the wire between server
  513. # and client. This relieves the implementor of a new drb
  514. # protocol layer with having to deal with these details.
  515. #
  516. # The user does not have to directly deal with this object in
  517. # normal use.
  518. class DRbMessage
  519. def initialize(config) # :nodoc:
  520. @load_limit = config[:load_limit]
  521. @argc_limit = config[:argc_limit]
  522. end
  523. def dump(obj, error=false) # :nodoc:
  524. obj = make_proxy(obj, error) if obj.kind_of? DRbUndumped
  525. begin
  526. str = Marshal::dump(obj)
  527. rescue
  528. str = Marshal::dump(make_proxy(obj, error))
  529. end
  530. [str.size].pack('N') + str
  531. end
  532. def load(soc) # :nodoc:
  533. begin
  534. sz = soc.read(4) # sizeof (N)
  535. rescue
  536. raise(DRbConnError, $!.message, $!.backtrace)
  537. end
  538. raise(DRbConnError, 'connection closed') if sz.nil?
  539. raise(DRbConnError, 'premature header') if sz.size < 4
  540. sz = sz.unpack('N')[0]
  541. raise(DRbConnError, "too large packet #{sz}") if @load_limit < sz
  542. begin
  543. str = soc.read(sz)
  544. rescue
  545. raise(DRbConnError, $!.message, $!.backtrace)
  546. end
  547. raise(DRbConnError, 'connection closed') if str.nil?
  548. raise(DRbConnError, 'premature marshal format(can\'t read)') if str.size < sz
  549. Thread.exclusive do
  550. begin
  551. save = Thread.current[:drb_untaint]
  552. Thread.current[:drb_untaint] = []
  553. Marshal::load(str)
  554. rescue NameError, ArgumentError
  555. DRbUnknown.new($!, str)
  556. ensure
  557. Thread.current[:drb_untaint].each do |x|
  558. x.untaint
  559. end
  560. Thread.current[:drb_untaint] = save
  561. end
  562. end
  563. end
  564. def send_request(stream, ref, msg_id, arg, b) # :nodoc:
  565. ary = []
  566. ary.push(dump(ref.__drbref))
  567. ary.push(dump(msg_id.id2name))
  568. ary.push(dump(arg.length))
  569. arg.each do |e|
  570. ary.push(dump(e))
  571. end
  572. ary.push(dump(b))
  573. stream.write(ary.join(''))
  574. rescue
  575. raise(DRbConnError, $!.message, $!.backtrace)
  576. end
  577. def recv_request(stream) # :nodoc:
  578. ref = load(stream)
  579. ro = DRb.to_obj(ref)
  580. msg = load(stream)
  581. argc = load(stream)
  582. raise ArgumentError, 'too many arguments' if @argc_limit < argc
  583. argv = Array.new(argc, nil)
  584. argc.times do |n|
  585. argv[n] = load(stream)
  586. end
  587. block = load(stream)
  588. return ro, msg, argv, block
  589. end
  590. def send_reply(stream, succ, result) # :nodoc:
  591. stream.write(dump(succ) + dump(result, !succ))
  592. rescue
  593. raise(DRbConnError, $!.message, $!.backtrace)
  594. end
  595. def recv_reply(stream) # :nodoc:
  596. succ = load(stream)
  597. result = load(stream)
  598. [succ, result]
  599. end
  600. private
  601. def make_proxy(obj, error=false)
  602. if error
  603. DRbRemoteError.new(obj)
  604. else
  605. DRbObject.new(obj)
  606. end
  607. end
  608. end
  609. # Module managing the underlying network protocol(s) used by drb.
  610. #
  611. # By default, drb uses the DRbTCPSocket protocol. Other protocols
  612. # can be defined. A protocol must define the following class methods:
  613. #
  614. # [open(uri, config)] Open a client connection to the server at +uri+,
  615. # using configuration +config+. Return a protocol
  616. # instance for this connection.
  617. # [open_server(uri, config)] Open a server listening at +uri+,
  618. # using configuration +config+. Return a
  619. # protocol instance for this listener.
  620. # [uri_option(uri, config)] Take a URI, possibly containing an option
  621. # component (e.g. a trailing '?param=val'),
  622. # and return a [uri, option] tuple.
  623. #
  624. # All of these methods should raise a DRbBadScheme error if the URI
  625. # does not identify the protocol they support (e.g. "druby:" for
  626. # the standard Ruby protocol). This is how the DRbProtocol module,
  627. # given a URI, determines which protocol implementation serves that
  628. # protocol.
  629. #
  630. # The protocol instance returned by #open_server must have the
  631. # following methods:
  632. #
  633. # [accept] Accept a new connection to the server. Returns a protocol
  634. # instance capable of communicating with the client.
  635. # [close] Close the server connection.
  636. # [uri] Get the URI for this server.
  637. #
  638. # The protocol instance returned by #open must have the following methods:
  639. #
  640. # [send_request (ref, msg_id, arg, b)]
  641. # Send a request to +ref+ with the given message id and arguments.
  642. # This is most easily implemented by calling DRbMessage.send_request,
  643. # providing a stream that sits on top of the current protocol.
  644. # [recv_reply]
  645. # Receive a reply from the server and return it as a [success-boolean,
  646. # reply-value] pair. This is most easily implemented by calling
  647. # DRb.recv_reply, providing a stream that sits on top of the
  648. # current protocol.
  649. # [alive?]
  650. # Is this connection still alive?
  651. # [close]
  652. # Close this connection.
  653. #
  654. # The protocol instance returned by #open_server().accept() must have
  655. # the following methods:
  656. #
  657. # [recv_request]
  658. # Receive a request from the client and return a [object, message,
  659. # args, block] tuple. This is most easily implemented by calling
  660. # DRbMessage.recv_request, providing a stream that sits on top of
  661. # the current protocol.
  662. # [send_reply(succ, result)]
  663. # Send a reply to the client. This is most easily implemented
  664. # by calling DRbMessage.send_reply, providing a stream that sits
  665. # on top of the current protocol.
  666. # [close]
  667. # Close this connection.
  668. #
  669. # A new protocol is registered with the DRbProtocol module using
  670. # the add_protocol method.
  671. #
  672. # For examples of other protocols, see DRbUNIXSocket in drb/unix.rb,
  673. # and HTTP0 in sample/http0.rb and sample/http0serv.rb in the full
  674. # drb distribution.
  675. module DRbProtocol
  676. # Add a new protocol to the DRbProtocol module.
  677. def add_protocol(prot)
  678. @protocol.push(prot)
  679. end
  680. module_function :add_protocol
  681. # Open a client connection to +uri+ with the configuration +config+.
  682. #
  683. # The DRbProtocol module asks each registered protocol in turn to
  684. # try to open the URI. Each protocol signals that it does not handle that
  685. # URI by raising a DRbBadScheme error. If no protocol recognises the
  686. # URI, then a DRbBadURI error is raised. If a protocol accepts the
  687. # URI, but an error occurs in opening it, a DRbConnError is raised.
  688. def open(uri, config, first=true)
  689. @protocol.each do |prot|
  690. begin
  691. return prot.open(uri, config)
  692. rescue DRbBadScheme
  693. rescue DRbConnError
  694. raise($!)
  695. rescue
  696. raise(DRbConnError, "#{uri} - #{$!.inspect}")
  697. end
  698. end
  699. if first && (config[:auto_load] != false)
  700. auto_load(uri, config)
  701. return open(uri, config, false)
  702. end
  703. raise DRbBadURI, 'can\'t parse uri:' + uri
  704. end
  705. module_function :open
  706. # Open a server listening for connections at +uri+ with
  707. # configuration +config+.
  708. #
  709. # The DRbProtocol module asks each registered protocol in turn to
  710. # try to open a server at the URI. Each protocol signals that it does
  711. # not handle that URI by raising a DRbBadScheme error. If no protocol
  712. # recognises the URI, then a DRbBadURI error is raised. If a protocol
  713. # accepts the URI, but an error occurs in opening it, the underlying
  714. # error is passed on to the caller.
  715. def open_server(uri, config, first=true)
  716. @protocol.each do |prot|
  717. begin
  718. return prot.open_server(uri, config)
  719. rescue DRbBadScheme
  720. end
  721. end
  722. if first && (config[:auto_load] != false)
  723. auto_load(uri, config)
  724. return open_server(uri, config, false)
  725. end
  726. raise DRbBadURI, 'can\'t parse uri:' + uri
  727. end
  728. module_function :open_server
  729. # Parse +uri+ into a [uri, option] pair.
  730. #
  731. # The DRbProtocol module asks each registered protocol in turn to
  732. # try to parse the URI. Each protocol signals that it does not handle that
  733. # URI by raising a DRbBadScheme error. If no protocol recognises the
  734. # URI, then a DRbBadURI error is raised.
  735. def uri_option(uri, config, first=true)
  736. @protocol.each do |prot|
  737. begin
  738. uri, opt = prot.uri_option(uri, config)
  739. # opt = nil if opt == ''
  740. return uri, opt
  741. rescue DRbBadScheme
  742. end
  743. end
  744. if first && (config[:auto_load] != false)
  745. auto_load(uri, config)
  746. return uri_option(uri, config, false)
  747. end
  748. raise DRbBadURI, 'can\'t parse uri:' + uri
  749. end
  750. module_function :uri_option
  751. def auto_load(uri, config) # :nodoc:
  752. if uri =~ /^drb([a-z0-9]+):/
  753. require("drb/#{$1}") rescue nil
  754. end
  755. end
  756. module_function :auto_load
  757. end
  758. # The default drb protocol.
  759. #
  760. # Communicates over a TCP socket.
  761. class DRbTCPSocket
  762. private
  763. def self.parse_uri(uri)
  764. if uri =~ /^druby:\/\/(.*?):(\d+)(\?(.*))?$/
  765. host = $1
  766. port = $2.to_i
  767. option = $4
  768. [host, port, option]
  769. else
  770. raise(DRbBadScheme, uri) unless uri =~ /^druby:/
  771. raise(DRbBadURI, 'can\'t parse uri:' + uri)
  772. end
  773. end
  774. public
  775. # Open a client connection to +uri+ using configuration +config+.
  776. def self.open(uri, config)
  777. host, port, option = parse_uri(uri)
  778. host.untaint
  779. port.untaint
  780. soc = TCPSocket.open(host, port)
  781. self.new(uri, soc, config)
  782. end
  783. def self.getservername
  784. host = Socket::gethostname
  785. begin
  786. Socket::gethostbyname(host)[0]
  787. rescue
  788. 'localhost'
  789. end
  790. end
  791. def self.open_server_inaddr_any(host, port)
  792. infos = Socket::getaddrinfo(host, nil,
  793. Socket::AF_UNSPEC,
  794. Socket::SOCK_STREAM,
  795. 0,
  796. Socket::AI_PASSIVE)
  797. family = infos.collect { |af, *_| af }.uniq
  798. case family
  799. when ['AF_INET']
  800. return TCPServer.open('0.0.0.0', port)
  801. when ['AF_INET6']
  802. return TCPServer.open('::', port)
  803. else
  804. return TCPServer.open(port)
  805. end
  806. end
  807. # Open a server listening for connections at +uri+ using
  808. # configuration +config+.
  809. def self.open_server(uri, config)
  810. uri = 'druby://:0' unless uri
  811. host, port, opt = parse_uri(uri)
  812. if host.size == 0
  813. host = getservername
  814. soc = open_server_inaddr_any(host, port)
  815. else
  816. soc = TCPServer.open(host, port)
  817. end
  818. port = soc.addr[1] if port == 0
  819. uri = "druby://#{host}:#{port}"
  820. self.new(uri, soc, config)
  821. end
  822. # Parse +uri+ into a [uri, option] pair.
  823. def self.uri_option(uri, config)
  824. host, port, option = parse_uri(uri)
  825. return "druby://#{host}:#{port}", option
  826. end
  827. # Create a new DRbTCPSocket instance.
  828. #
  829. # +uri+ is the URI we are connected to.
  830. # +soc+ is the tcp socket we are bound to. +config+ is our
  831. # configuration.
  832. def initialize(uri, soc, config={})
  833. @uri = uri
  834. @socket = soc
  835. @config = config
  836. @acl = config[:tcp_acl]
  837. @msg = DRbMessage.new(config)
  838. set_sockopt(@socket)
  839. end
  840. # Get the URI that we are connected to.
  841. attr_reader :uri
  842. # Get the address of our TCP peer (the other end of the socket
  843. # we are bound to.
  844. def peeraddr
  845. @socket.peeraddr
  846. end
  847. # Get the socket.
  848. def stream; @socket; end
  849. # On the client side, send a request to the server.
  850. def send_request(ref, msg_id, arg, b)
  851. @msg.send_request(stream, ref, msg_id, arg, b)
  852. end
  853. # On the server side, receive a request from the client.
  854. def recv_request
  855. @msg.recv_request(stream)
  856. end
  857. # On the server side, send a reply to the client.
  858. def send_reply(succ, result)
  859. @msg.send_reply(stream, succ, result)
  860. end
  861. # On the client side, receive a reply from the server.
  862. def recv_reply
  863. @msg.recv_reply(stream)
  864. end
  865. public
  866. # Close the connection.
  867. #
  868. # If this is an instance returned by #open_server, then this stops
  869. # listening for new connections altogether. If this is an instance
  870. # returned by #open or by #accept, then it closes this particular
  871. # client-server session.
  872. def close
  873. if @socket
  874. @socket.close
  875. @socket = nil
  876. end
  877. end
  878. # On the server side, for an instance returned by #open_server,
  879. # accept a client connection and return a new instance to handle
  880. # the server's side of this client-server session.
  881. def accept
  882. while true
  883. s = @socket.accept
  884. break if (@acl ? @acl.allow_socket?(s) : true)
  885. s.close
  886. end
  887. self.class.new(nil, s, @config)
  888. end
  889. # Check to see if this connection is alive.
  890. def alive?
  891. return false unless @socket
  892. if IO.select([@socket], nil, nil, 0)
  893. close
  894. return false
  895. end
  896. true
  897. end
  898. def set_sockopt(soc) # :nodoc:
  899. soc.setsockopt(Socket::IPPROTO_TCP, Socket::TCP_NODELAY, 1)
  900. soc.fcntl(Fcntl::F_SETFD, Fcntl::FD_CLOEXEC) if defined? Fcntl::FD_CLOEXEC
  901. end
  902. end
  903. module DRbProtocol
  904. @protocol = [DRbTCPSocket] # default
  905. end
  906. class DRbURIOption # :nodoc: I don't understand the purpose of this class...
  907. def initialize(option)
  908. @option = option.to_s
  909. end
  910. attr :option
  911. def to_s; @option; end
  912. def ==(other)
  913. return false unless DRbURIOption === other
  914. @option == other.option
  915. end
  916. def hash
  917. @option.hash
  918. end
  919. alias eql? ==
  920. end
  921. # Object wrapping a reference to a remote drb object.
  922. #
  923. # Method calls on this object are relayed to the remote
  924. # object that this object is a stub for.
  925. class DRbObject
  926. # Unmarshall a marshalled DRbObject.
  927. #
  928. # If the referenced object is located within the local server, then
  929. # the object itself is returned. Otherwise, a new DRbObject is
  930. # created to act as a stub for the remote referenced object.
  931. def self._load(s)
  932. uri, ref = Marshal.load(s)
  933. if DRb.here?(uri)
  934. obj = DRb.to_obj(ref)
  935. if ((! obj.tainted?) && Thread.current[:drb_untaint])
  936. Thread.current[:drb_untaint].push(obj)
  937. end
  938. return obj
  939. end
  940. self.new_with(uri, ref)
  941. end
  942. def self.new_with(uri, ref)
  943. it = self.allocate
  944. it.instance_variable_set('@uri', uri)
  945. it.instance_variable_set('@ref', ref)
  946. it
  947. end
  948. # Create a new DRbObject from a URI alone.
  949. def self.new_with_uri(uri)
  950. self.new(nil, uri)
  951. end
  952. # Marshall this object.
  953. #
  954. # The URI and ref of the object are marshalled.
  955. def _dump(lv)
  956. Marshal.dump([@uri, @ref])
  957. end
  958. # Create a new remote object stub.
  959. #
  960. # +obj+ is the (local) object we want to create a stub for. Normally
  961. # this is +nil+. +uri+ is the URI of the remote object that this
  962. # will be a stub for.
  963. def initialize(obj, uri=nil)
  964. @uri = nil
  965. @ref = nil
  966. if obj.nil?
  967. return if uri.nil?
  968. @uri, option = DRbProtocol.uri_option(uri, DRb.config)
  969. @ref = DRbURIOption.new(option) unless option.nil?
  970. else
  971. @uri = uri ? uri : (DRb.uri rescue nil)
  972. @ref = obj ? DRb.to_id(obj) : nil
  973. end
  974. end
  975. # Get the URI of the remote object.
  976. def __drburi
  977. @uri
  978. end
  979. # Get the reference of the object, if local.
  980. def __drbref
  981. @ref
  982. end
  983. undef :to_s
  984. undef :to_a if respond_to?(:to_a)
  985. def respond_to?(msg_id, priv=false)
  986. case msg_id
  987. when :_dump
  988. true
  989. when :marshal_dump
  990. false
  991. else
  992. method_missing(:respond_to?, msg_id, priv)
  993. end
  994. end
  995. # Routes method calls to the referenced object.
  996. def method_missing(msg_id, *a, &b)
  997. if DRb.here?(@uri)
  998. obj = DRb.to_obj(@ref)
  999. DRb.current_server.check_insecure_method(obj, msg_id)
  1000. return obj.__send__(msg_id, *a, &b)
  1001. end
  1002. succ, result = self.class.with_friend(@uri) do
  1003. DRbConn.open(@uri) do |conn|
  1004. conn.send_message(self, msg_id, a, b)
  1005. end
  1006. end
  1007. if succ
  1008. return result
  1009. elsif DRbUnknown === result
  1010. raise result
  1011. else
  1012. bt = self.class.prepare_backtrace(@uri, result)
  1013. result.set_backtrace(bt + caller)
  1014. raise result
  1015. end
  1016. end
  1017. def self.with_friend(uri)
  1018. friend = DRb.fetch_server(uri)
  1019. return yield() unless friend
  1020. save = Thread.current['DRb']
  1021. Thread.current['DRb'] = { 'server' => friend }
  1022. return yield
  1023. ensure
  1024. Thread.current['DRb'] = save if friend
  1025. end
  1026. def self.prepare_backtrace(uri, result)
  1027. prefix = "(#{uri}) "
  1028. bt = []
  1029. result.backtrace.each do |x|
  1030. break if /`__send__'$/ =~ x
  1031. if /^\(druby:\/\// =~ x
  1032. bt.push(x)
  1033. else
  1034. bt.push(prefix + x)
  1035. end
  1036. end
  1037. bt
  1038. end
  1039. def pretty_print(q) # :nodoc:
  1040. q.pp_object(self)
  1041. end
  1042. def pretty_print_cycle(q) # :nodoc:
  1043. q.object_address_group(self) {
  1044. q.breakable
  1045. q.text '...'
  1046. }
  1047. end
  1048. end
  1049. # Class handling the connection between a DRbObject and the
  1050. # server the real object lives on.
  1051. #
  1052. # This class maintains a pool of connections, to reduce the
  1053. # overhead of starting and closing down connections for each
  1054. # method call.
  1055. #
  1056. # This class is used internally by DRbObject. The user does
  1057. # not normally need to deal with it directly.
  1058. class DRbConn
  1059. POOL_SIZE = 16 # :nodoc:
  1060. @mutex = Mutex.new
  1061. @pool = []
  1062. def self.open(remote_uri) # :nodoc:
  1063. begin
  1064. conn = nil
  1065. @mutex.synchronize do
  1066. #FIXME
  1067. new_pool = []
  1068. @pool.each do |c|
  1069. if conn.nil? and c.uri == remote_uri
  1070. conn = c if c.alive?
  1071. else
  1072. new_pool.push c
  1073. end
  1074. end
  1075. @pool = new_pool
  1076. end
  1077. conn = self.new(remote_uri) unless conn
  1078. succ, result = yield(conn)
  1079. return succ, result
  1080. ensure
  1081. if conn
  1082. if succ
  1083. @mutex.synchronize do
  1084. @pool.unshift(conn)
  1085. @pool.pop.close while @pool.size > POOL_SIZE
  1086. end
  1087. else
  1088. conn.close
  1089. end
  1090. end
  1091. end
  1092. end
  1093. def initialize(remote_uri) # :nodoc:
  1094. @uri = remote_uri
  1095. @protocol = DRbProtocol.open(remote_uri, DRb.config)
  1096. end
  1097. attr_reader :uri # :nodoc:
  1098. def send_message(ref, msg_id, arg, block) # :nodoc:
  1099. @protocol.send_request(ref, msg_id, arg, block)
  1100. @protocol.recv_reply
  1101. end
  1102. def close # :nodoc:
  1103. @protocol.close
  1104. @protocol = nil
  1105. end
  1106. def alive? # :nodoc:
  1107. return false unless @protocol
  1108. @protocol.alive?
  1109. end
  1110. end
  1111. # Class representing a drb server instance.
  1112. #
  1113. # A DRbServer must be running in the local process before any incoming
  1114. # dRuby calls can be accepted, or any local objects can be passed as
  1115. # dRuby references to remote processes, even if those local objects are
  1116. # never actually called remotely. You do not need to start a DRbServer
  1117. # in the local process if you are only making outgoing dRuby calls
  1118. # passing marshalled parameters.
  1119. #
  1120. # Unless multiple servers are being used, the local DRbServer is normally
  1121. # started by calling DRb.start_service.
  1122. class DRbServer
  1123. @@acl = nil
  1124. @@idconv = DRbIdConv.new
  1125. @@secondary_server = nil
  1126. @@argc_limit = 256
  1127. @@load_limit = 256 * 102400
  1128. @@verbose = false
  1129. @@safe_level = 0
  1130. # Set the default value for the :argc_limit option.
  1131. #
  1132. # See #new(). The initial default value is 256.
  1133. def self.default_argc_limit(argc)
  1134. @@argc_limit = argc
  1135. end
  1136. # Set the default value for the :load_limit option.
  1137. #
  1138. # See #new(). The initial default value is 25 MB.
  1139. def self.default_load_limit(sz)
  1140. @@load_limit = sz
  1141. end
  1142. # Set the default value for the :acl option.
  1143. #
  1144. # See #new(). The initial default value is nil.
  1145. def self.default_acl(acl)
  1146. @@acl = acl
  1147. end
  1148. # Set the default value for the :id_conv option.
  1149. #
  1150. # See #new(). The initial default value is a DRbIdConv instance.
  1151. def self.default_id_conv(idconv)
  1152. @@idconv = idconv
  1153. end
  1154. def self.default_safe_level(level)
  1155. @@safe_level = level
  1156. end
  1157. # Set the default value of the :verbose option.
  1158. #
  1159. # See #new(). The initial default value is false.
  1160. def self.verbose=(on)
  1161. @@verbose = on
  1162. end
  1163. # Get the default value of the :verbose option.
  1164. def self.verbose
  1165. @@verbose
  1166. end
  1167. def self.make_config(hash={}) # :nodoc:
  1168. default_config = {
  1169. :idconv => @@idconv,
  1170. :verbose => @@verbose,
  1171. :tcp_acl => @@acl,
  1172. :load_limit => @@load_limit,
  1173. :argc_limit => @@argc_limit,
  1174. :safe_level => @@safe_level
  1175. }
  1176. default_config.update(hash)
  1177. end
  1178. # Create a new DRbServer instance.
  1179. #
  1180. # +uri+ is the URI to bind to. This is normally of the form
  1181. # 'druby://<hostname>:<port>' where <hostname> is a hostname of
  1182. # the local machine. If nil, then the system's default hostname
  1183. # will be bound to, on a port selected by the system; these value
  1184. # can be retrieved from the +uri+ attribute. 'druby:' specifies
  1185. # the default dRuby transport protocol: another protocol, such
  1186. # as 'drbunix:', can be specified instead.
  1187. #
  1188. # +front+ is the front object for the server, that is, the object
  1189. # to which remote method calls on the server will be passed. If
  1190. # nil, then the server will not accept remote method calls.
  1191. #
  1192. # If +config_or_acl+ is a hash, it is the configuration to
  1193. # use for this server. The following options are recognised:
  1194. #
  1195. # :idconv :: an id-to-object conversion object. This defaults
  1196. # to an instance of the class DRb::DRbIdConv.
  1197. # :verbose :: if true, all unsuccessful remote calls on objects
  1198. # in the server will be logged to $stdout. false
  1199. # by default.
  1200. # :tcp_acl :: the access control list for this server. See
  1201. # the ACL class from the main dRuby distribution.
  1202. # :load_limit :: the maximum message size in bytes accepted by
  1203. # the server. Defaults to 25 MB (26214400).
  1204. # :argc_limit :: the maximum number of arguments to a remote
  1205. # method accepted by the server. Defaults to
  1206. # 256.
  1207. #
  1208. # The default values of these options can be modified on
  1209. # a class-wide basis by the class methods #default_argc_limit,
  1210. # #default_load_limit, #default_acl, #default_id_conv,
  1211. # and #verbose=
  1212. #
  1213. # If +config_or_acl+ is not a hash, but is not nil, it is
  1214. # assumed to be the access control list for this server.
  1215. # See the :tcp_acl option for more details.
  1216. #
  1217. # If no other server is currently set as the primary server,
  1218. # this will become the primary server.
  1219. #
  1220. # The server will immediately start running in its own thread.
  1221. def initialize(uri=nil, front=nil, config_or_acl=nil)
  1222. if Hash === config_or_acl
  1223. config = config_or_acl.dup
  1224. else
  1225. acl = config_or_acl || @@acl
  1226. config = {
  1227. :tcp_acl => acl
  1228. }
  1229. end
  1230. @config = self.class.make_config(config)
  1231. @protocol = DRbProtocol.open_server(uri, @config)
  1232. @uri = @protocol.uri
  1233. @front = front
  1234. @idconv = @config[:idconv]
  1235. @safe_level = @config[:safe_level]
  1236. @grp = ThreadGroup.new
  1237. @thread = run
  1238. DRb.regist_server(self)
  1239. end
  1240. # The URI of this DRbServer.
  1241. attr_reader :uri
  1242. # The main thread of this DRbServer.
  1243. #
  1244. # This is the thread that listens for and accepts connections
  1245. # from clients, not that handles each client's request-response
  1246. # session.
  1247. attr_reader :thread
  1248. # The front object of the DRbServer.
  1249. #
  1250. # This object receives remote method calls made on the server's
  1251. # URI alone, with an object id.
  1252. attr_reader :front
  1253. # The configuration of this DRbServer
  1254. attr_reader :config
  1255. attr_reader :safe_level
  1256. # Set whether to operate in verbose mode.
  1257. #
  1258. # In verbose mode, failed calls are logged to stdout.
  1259. def verbose=(v); @config[:verbose]=v; end
  1260. # Get whether the server is in verbose mode.
  1261. #
  1262. # In verbose mode, failed calls are logged to stdout.
  1263. def verbose; @config[:verbose]; end
  1264. # Is this server alive?
  1265. def alive?
  1266. @thread.alive?
  1267. end
  1268. # Stop this server.
  1269. def stop_service
  1270. DRb.remove_server(self)
  1271. if Thread.current['DRb'] && Thread.current['DRb']['server'] == self
  1272. Thread.current['DRb']['stop_service'] = true
  1273. else
  1274. @thread.kill
  1275. end
  1276. end
  1277. # Convert a dRuby reference to the local object it refers to.
  1278. def to_obj(ref)
  1279. return front if ref.nil?
  1280. return front[ref.to_s] if DRbURIOption === ref
  1281. @idconv.to_obj(ref)
  1282. end
  1283. # Convert a local object to a dRuby reference.
  1284. def to_id(obj)
  1285. return nil if obj.__id__ == front.__id__
  1286. @idconv.to_id(obj)
  1287. end
  1288. private
  1289. def kill_sub_thread
  1290. Thread.new do
  1291. grp = ThreadGroup.new
  1292. grp.add(Thread.current)
  1293. list = @grp.list
  1294. while list.size > 0
  1295. list.each do |th|
  1296. th.kill if th.alive?
  1297. end
  1298. list = @grp.list
  1299. end
  1300. end
  1301. end
  1302. def run
  1303. Thread.start do
  1304. begin
  1305. while true
  1306. main_loop
  1307. end
  1308. ensure
  1309. @protocol.close if @protocol
  1310. kill_sub_thread
  1311. end
  1312. end
  1313. end
  1314. # List of insecure methods.
  1315. #
  1316. # These methods are not callable via dRuby.
  1317. INSECURE_METHOD = [
  1318. :__send__
  1319. ]
  1320. # Has a method been included in the list of insecure methods?
  1321. def insecure_method?(msg_id)
  1322. INSECURE_METHOD.include?(msg_id)
  1323. end
  1324. # Coerce an object to a string, providing our own representation if
  1325. # to_s is not defined for the object.
  1326. def any_to_s(obj)
  1327. obj.to_s + ":#{obj.class}"
  1328. rescue
  1329. sprintf("#<%s:0x%lx>", obj.class, obj.__id__)
  1330. end
  1331. # Check that a method is callable via dRuby.
  1332. #
  1333. # +obj+ is the object we want to invoke the method on. +msg_id+ is the
  1334. # method name, as a Symbol.
  1335. #
  1336. # If the method is an insecure method (see #insecure_method?) a
  1337. # SecurityError is thrown. If the method is private or undefined,
  1338. # a NameError is thrown.
  1339. def check_insecure_method(obj, msg_id)
  1340. return true if Proc === obj && msg_id == :__drb_yield
  1341. raise(ArgumentError, "#{any_to_s(msg_id)} is not a symbol") unless Symbol == msg_id.class
  1342. raise(SecurityError, "insecure method `#{msg_id}'") if insecure_method?(msg_id)
  1343. if obj.private_methods.include?(msg_id.to_s)
  1344. desc = any_to_s(obj)
  1345. raise NoMethodError, "private method `#{msg_id}' called for #{desc}"
  1346. elsif obj.protected_methods.include?(msg_id.to_s)
  1347. desc = any_to_s(obj)
  1348. raise NoMethodError, "protected method `#{msg_id}' called for #{desc}"
  1349. else
  1350. true
  1351. end
  1352. end
  1353. public :check_insecure_method
  1354. class InvokeMethod # :nodoc:
  1355. def initialize(drb_server, client)
  1356. @drb_server = drb_server
  1357. @safe_level = drb_server.safe_level
  1358. @client = client
  1359. end
  1360. def perform
  1361. @result = nil
  1362. @succ = false
  1363. setup_message
  1364. if $SAFE < @safe_level
  1365. info = Thread.current['DRb']
  1366. if @block
  1367. @result = Thread.new {
  1368. Thread.current['DRb'] = info
  1369. $SAFE = @safe_level
  1370. perform_with_block
  1371. }.value
  1372. else
  1373. @result = Thread.new {
  1374. Thread.current['DRb'] = info
  1375. $SAFE = @safe_level
  1376. perform_without_block
  1377. }.value
  1378. end
  1379. else
  1380. if @block
  1381. @result = perform_with_block
  1382. else
  1383. @result = perform_without_block
  1384. end
  1385. end
  1386. @succ = true
  1387. if @msg_id == :to_ary && @result.class == Array
  1388. @result = DRbArray.new(@result)
  1389. end
  1390. return @succ, @result
  1391. rescue StandardError, ScriptError, Interrupt
  1392. @result = $!
  1393. return @succ, @result
  1394. end
  1395. private
  1396. def init_with_client
  1397. obj, msg, argv, block = @client.recv_request
  1398. @obj = obj
  1399. @msg_id = msg.intern
  1400. @argv = argv
  1401. @block = block
  1402. end
  1403. def check_insecure_method
  1404. @drb_server.check_insecure_method(@obj, @msg_id)
  1405. end
  1406. def setup_message
  1407. init_with_client
  1408. check_insecure_method
  1409. end
  1410. def perform_without_block
  1411. if Proc === @obj && @msg_id == :__drb_yield
  1412. if @argv.size == 1
  1413. ary = @argv
  1414. else
  1415. ary = [@argv]
  1416. end
  1417. ary.collect(&@obj)[0]
  1418. else
  1419. @obj.__send__(@msg_id, *@argv)
  1420. end
  1421. end
  1422. end
  1423. if RUBY_VERSION >= '1.8'
  1424. require 'drb/invokemethod'
  1425. class InvokeMethod
  1426. include InvokeMethod18Mixin
  1427. end
  1428. else
  1429. require 'drb/invokemethod16'
  1430. class InvokeMethod
  1431. include InvokeMethod16Mixin
  1432. end
  1433. end
  1434. # The main loop performed by a DRbServer's internal thread.
  1435. #
  1436. # Accepts a connection from a client, and starts up its own
  1437. # thread to handle it. This thread loops, receiving requests
  1438. # from the client, invoking them on a local object, and
  1439. # returning responses, until the client closes the connection
  1440. # or a local method call fails.
  1441. def main_loop
  1442. Thread.start(@protocol.accept) do |client|
  1443. @grp.add Thread.current
  1444. Thread.current['DRb'] = { 'client' => client ,
  1445. 'server' => self }
  1446. loop do
  1447. begin
  1448. succ = false
  1449. invoke_method = InvokeMethod.new(self, client)
  1450. succ, result = invoke_method.perform
  1451. if !succ && verbose
  1452. p result
  1453. result.backtrace.each do |x|
  1454. puts x
  1455. end
  1456. end
  1457. client.send_reply(succ, result) rescue nil
  1458. ensure
  1459. client.close unless succ
  1460. if Thread.current['DRb']['stop_service']
  1461. Thread.new { stop_service }
  1462. end
  1463. break unless succ
  1464. end
  1465. end
  1466. end
  1467. end
  1468. end
  1469. @primary_server = nil
  1470. # Start a dRuby server locally.
  1471. #
  1472. # The new dRuby server will become the primary server, even
  1473. # if another server is currently the primary server.
  1474. #
  1475. # +uri+ is the URI for the server to bind to. If nil,
  1476. # the server will bind to random port on the default local host
  1477. # name and use the default dRuby protocol.
  1478. #
  1479. # +front+ is the server's front object. This may be nil.
  1480. #
  1481. # +config+ is the configuration for the new server. This may
  1482. # be nil.
  1483. #
  1484. # See DRbServer::new.
  1485. def start_service(uri=nil, front=nil, config=nil)
  1486. @primary_server = DRbServer.new(uri, front, config)
  1487. end
  1488. module_function :start_service
  1489. # The primary local dRuby server.
  1490. #
  1491. # This is the server created by the #start_service call.
  1492. attr_accessor :primary_server
  1493. module_function :primary_server=, :primary_server
  1494. # Get the 'current' server.
  1495. #
  1496. # In the context of execution taking place within the main
  1497. # thread of a dRuby server (typically, as a result of a remote
  1498. # call on the server or one of its objects), the current
  1499. # server is that server. Otherwise, the cu

Large files files are truncated, but you can click here to view the full file