1 | require 'socket'
|
---|
2 | require 'drb/drb'
|
---|
3 | require 'tmpdir'
|
---|
4 |
|
---|
5 | raise(LoadError, "UNIXServer is required") unless defined?(UNIXServer)
|
---|
6 |
|
---|
7 | module DRb
|
---|
8 |
|
---|
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
|
---|
20 |
|
---|
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
|
---|
27 |
|
---|
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
|
---|
47 |
|
---|
48 | self.new(uri, soc, config, true)
|
---|
49 | end
|
---|
50 |
|
---|
51 | def self.uri_option(uri, config)
|
---|
52 | filename, option = parse_uri(uri)
|
---|
53 | return "drbunix:#{filename}", option
|
---|
54 | end
|
---|
55 |
|
---|
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
|
---|
87 |
|
---|
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
|
---|
96 |
|
---|
97 | def accept
|
---|
98 | s = @socket.accept
|
---|
99 | self.class.new(nil, s, @config)
|
---|
100 | end
|
---|
101 |
|
---|
102 | def set_sockopt(soc)
|
---|
103 | soc.fcntl(Fcntl::F_SETFL, Fcntl::FD_CLOEXEC) if defined? Fcntl::FD_CLOEXEC
|
---|
104 | end
|
---|
105 | end
|
---|
106 |
|
---|
107 | DRbProtocol.add_protocol(DRbUNIXSocket)
|
---|
108 | end
|
---|