1# frozen_string_literal: false 2require 'socket' 3require_relative 'drb' 4require 'tmpdir' 5 6raise(LoadError, "UNIXServer is required") unless defined?(UNIXServer) 7 8module DRb 9 10 # Implements DRb over a UNIX socket 11 # 12 # DRb UNIX socket URIs look like <code>drbunix:<path>?<option></code>. The 13 # option is optional. 14 15 class DRbUNIXSocket < DRbTCPSocket 16 # :stopdoc: 17 def self.parse_uri(uri) 18 if /\Adrbunix:(.*?)(\?(.*))?\z/ =~ uri 19 filename = $1 20 option = $3 21 [filename, option] 22 else 23 raise(DRbBadScheme, uri) unless uri.start_with?('drbunix:') 24 raise(DRbBadURI, 'can\'t parse uri:' + uri) 25 end 26 end 27 28 def self.open(uri, config) 29 filename, = parse_uri(uri) 30 filename.untaint 31 soc = UNIXSocket.open(filename) 32 self.new(uri, soc, config) 33 end 34 35 def self.open_server(uri, config) 36 filename, = parse_uri(uri) 37 if filename.size == 0 38 soc = temp_server 39 filename = soc.path 40 uri = 'drbunix:' + soc.path 41 else 42 soc = UNIXServer.open(filename) 43 end 44 owner = config[:UNIXFileOwner] 45 group = config[:UNIXFileGroup] 46 if owner || group 47 require 'etc' 48 owner = Etc.getpwnam( owner ).uid if owner 49 group = Etc.getgrnam( group ).gid if group 50 File.chown owner, group, filename 51 end 52 mode = config[:UNIXFileMode] 53 File.chmod(mode, filename) if mode 54 55 self.new(uri, soc, config, true) 56 end 57 58 def self.uri_option(uri, config) 59 filename, option = parse_uri(uri) 60 return "drbunix:#{filename}", option 61 end 62 63 def initialize(uri, soc, config={}, server_mode = false) 64 super(uri, soc, config) 65 set_sockopt(@socket) 66 @server_mode = server_mode 67 @acl = nil 68 end 69 70 # import from tempfile.rb 71 Max_try = 10 72 private 73 def self.temp_server 74 tmpdir = Dir::tmpdir 75 n = 0 76 while true 77 begin 78 tmpname = sprintf('%s/druby%d.%d', tmpdir, $$, n) 79 lock = tmpname + '.lock' 80 unless File.exist?(tmpname) or File.exist?(lock) 81 Dir.mkdir(lock) 82 break 83 end 84 rescue 85 raise "cannot generate tempfile `%s'" % tmpname if n >= Max_try 86 #sleep(1) 87 end 88 n += 1 89 end 90 soc = UNIXServer.new(tmpname) 91 Dir.rmdir(lock) 92 soc 93 end 94 95 public 96 def close 97 return unless @socket 98 shutdown # DRbProtocol#shutdown 99 path = @socket.path if @server_mode 100 @socket.close 101 File.unlink(path) if @server_mode 102 @socket = nil 103 close_shutdown_pipe 104 end 105 106 def accept 107 s = accept_or_shutdown 108 return nil unless s 109 self.class.new(nil, s, @config) 110 end 111 112 def set_sockopt(soc) 113 # no-op for now 114 end 115 end 116 117 DRbProtocol.add_protocol(DRbUNIXSocket) 118 # :startdoc: 119end 120