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