Imported File#ftype spec from rubyspecs.
[rbx.git] / lib / drb / unix.rb
blob57feed8301a64b42fa2f6e6c3b1f6b4ee9c8b02a
1 require 'socket'
2 require 'drb/drb'
3 require 'tmpdir'
5 raise(LoadError, "UNIXServer is required") unless defined?(UNIXServer)
7 module DRb
9   class DRbUNIXSocket < DRbTCPSocket
10     def self.parse_uri(uri)
11       if /^drbunix:(.*?)(\?(.*))?$/ =~ uri 
12         filename = $1
13         option = $3
14         [filename, option]
15       else
16         raise(DRbBadScheme, uri) unless uri =~ /^drbunix:/
17         raise(DRbBadURI, 'can\'t parse uri:' + uri)
18       end
19     end
21     def self.open(uri, config)
22       filename, option = parse_uri(uri)
23       filename.untaint
24       soc = UNIXSocket.open(filename)
25       self.new(uri, soc, config)
26     end
28     def self.open_server(uri, config)
29       filename, option = parse_uri(uri)
30       if filename.size == 0
31         soc = temp_server
32         filename = soc.path
33         uri = 'drbunix:' + soc.path
34       else
35         soc = UNIXServer.open(filename)
36       end
37       owner = config[:UNIXFileOwner]
38       group = config[:UNIXFileGroup]
39       if owner || group
40         require 'etc'
41         owner = Etc.getpwnam( owner ).uid  if owner
42         group = Etc.getgrnam( group ).gid  if group
43         File.chown owner, group, filename
44       end
45       mode = config[:UNIXFileMode]
46       File.chmod(mode, filename) if mode
48       self.new(uri, soc, config, true)
49     end
51     def self.uri_option(uri, config)
52       filename, option = parse_uri(uri)
53       return "drbunix:#{filename}", option
54     end
56     def initialize(uri, soc, config={}, server_mode = false)
57       super(uri, soc, config)
58       set_sockopt(@socket)
59       @server_mode = server_mode
60       @acl = nil
61     end
62     
63     # import from tempfile.rb
64     Max_try = 10
65     private
66     def self.temp_server
67       tmpdir = Dir::tmpdir
68       n = 0
69       while true
70         begin
71           tmpname = sprintf('%s/druby%d.%d', tmpdir, $$, n)
72           lock = tmpname + '.lock'
73           unless File.exist?(tmpname) or File.exist?(lock)
74             Dir.mkdir(lock)
75             break
76           end
77         rescue
78           raise "cannot generate tempfile `%s'" % tmpname if n >= Max_try
79           #sleep(1)
80         end
81         n += 1
82       end
83       soc = UNIXServer.new(tmpname)
84       Dir.rmdir(lock)
85       soc
86     end
88     public
89     def close
90       return unless @socket
91       path = @socket.path if @server_mode
92       @socket.close
93       File.unlink(path) if @server_mode
94       @socket = nil
95     end
97     def accept
98       s = @socket.accept
99       self.class.new(nil, s, @config)
100     end
102     def set_sockopt(soc)
103       soc.fcntl(Fcntl::F_SETFL, Fcntl::FD_CLOEXEC) if defined? Fcntl::FD_CLOEXEC
104     end
105   end
107   DRbProtocol.add_protocol(DRbUNIXSocket)