Passing File Descriptors?

W

Worky Workerson

Is there a ruby way to pass file descriptors to separate processes?
I'm thinking of interfacing with a C program, which uses the
SCM_RIGHTS cmsg over a unix-domain socket ... is this idiom
implemented in Ruby? How would I marshall an IO object into (and out
of) the integer file descriptor, or does this "just work"?

Thanks!
-Mike
 
R

Robert Klemme

Is there a ruby way to pass file descriptors to separate processes?
I'm thinking of interfacing with a C program, which uses the
SCM_RIGHTS cmsg over a unix-domain socket ... is this idiom
implemented in Ruby? How would I marshall an IO object into (and out
of) the integer file descriptor, or does this "just work"?

Untested: You can determine the descriptor id via io.fileno. The you
can pass that to the child process via main's args when you exec after
fork. Then the child should be able to reuse that descriptor.
Alternatively you can of course transport the descriptor id via an
environment variable.

Kind regards

robert
 
G

Gary Wright

Is there a ruby way to pass file descriptors to separate processes?
I'm thinking of interfacing with a C program, which uses the
SCM_RIGHTS cmsg over a unix-domain socket ... is this idiom
implemented in Ruby? How would I marshall an IO object into (and out
of) the integer file descriptor, or does this "just work"?

After a little investigation, this turned out to be easier than
I thought. The following code was tested on Mac OS X with ruby 1.8.5.
There are three files below, don't cut and paste the whole thing:

socketpair.rb # example with parent/child

server.rb # example with unrelated processes
client.rb

Socketpair.rb and client.rb both take a single argument, the name
of the data file to open.

Start server.rb before running client.rb.

If you try this on something other than Mac OS X ruby 1.8.5, let us
know how it works.

Gary Wright


$ cat socketpair.rb
# Scenario 1: parent and child related via fork
require 'socket'

read, write = UNIXSocket.pair

puts "parent end: #{read.inspect}, #{read.fileno}"
puts "child end: #{write.inspect}, #{write.fileno}"

pid = fork {
file = File.open(ARGV[0])
puts "child is sending: #{file.inspect}/#{file.fileno} connected
to #{ARGV[0]}"
write.send_io(file)
exit
}

thefile = read.recv_io
puts "parent received: #{thefile.inspect}/#{thefile.fileno}, contents:"
puts thefile.read

# end of scenario 1

$ cat server.rb
require 'socket'

serv = UNIXServer.new("/tmp/server")
p "server listening for connections: #{serv.inspect}"

client = serv.accept
p "received connection: #{client.inspect}"

clientfile = client.recv_io
puts "parent received fd: #{clientfile.fileno}, contents:"

puts clientfile.read
# end of server.rb


$ cat client.rb
require 'socket'

server = UNIXSocket.new("/tmp/server")
puts "connected to : #{server.inspect}"

fd = File.open(ARGV[0])
puts "child is sending fd: #{fd.fileno} connected to #{ARGV[0]}"

server.send_io(fd) # we are *not* sending the data!

exit
 
G

Gary Wright

Is there a ruby way to pass file descriptors to separate processes?
I'm thinking of interfacing with a C program, which uses the
SCM_RIGHTS cmsg over a unix-domain socket ... is this idiom
implemented in Ruby? How would I marshall an IO object into (and out
of) the integer file descriptor, or does this "just work"?

In case folks were looking for a use case.

A client makes a request to a server which opens the file
and sends the opened file descriptor back to the client.
Presumably the server process has special permissions to allow it
access to the files that the client doesn't have. The server
can also implement any additional security controls.

The client gets to read and write a file without having had
permission to open the file directly.

This only works via Unix Domain sockets and so it only
works between processes on the same machine. It won't work
across a network.

Gary Wright
 
W

Worky Workerson

After a little investigation, this turned out to be easier than
I thought. ...
clientfile = client.recv_io
puts "parent received fd: #{clientfile.fileno}, contents:"

Sweet, thanks! I guess I had missed the {send,recv}_io methods.
They're not in the Ruby book ... guess I should have done to the
online docs. Ruby does make this trivial ... even works with my
existing C program.

-Mike
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,744
Messages
2,569,484
Members
44,903
Latest member
orderPeak8CBDGummies

Latest Threads

Top