PageRenderTime 68ms CodeModel.GetById 25ms RepoModel.GetById 1ms app.codeStats 0ms

/components/ruby-2.1.0/lib/drb/drb.rb

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