Forum: Ruby Passing File Descriptors?

Announcement (2017-05-07): www.ruby-forum.com is now read-only since I unfortunately do not have the time to support and maintain the forum any more. Please see rubyonrails.org/community and ruby-lang.org/en/community for other Rails- und Ruby-related community platforms.
F715fc778879b69712cb8e25a4e5590b?d=identicon&s=25 Worky Workerson (worky)
on 2007-03-19 17:43
(Received via mailing list)
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
E0d864d9677f3c1482a20152b7cac0e2?d=identicon&s=25 Robert Klemme (Guest)
on 2007-03-19 18:28
(Received via mailing list)
On 19.03.2007 17:43, Worky Workerson wrote:
> 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
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 Gary Wright (Guest)
on 2007-03-19 23:08
(Received via mailing list)
On Mar 19, 2007, at 12:43 PM, Worky Workerson wrote:
> 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
E7559e558ececa67c40f452483b9ac8c?d=identicon&s=25 Gary Wright (Guest)
on 2007-03-19 23:18
(Received via mailing list)
On Mar 19, 2007, at 12:43 PM, Worky Workerson wrote:

> 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
F715fc778879b69712cb8e25a4e5590b?d=identicon&s=25 Worky Workerson (worky)
on 2007-03-20 18:13
(Received via mailing list)
On 3/19/07, Gary Wright <gwtmp01@mac.com> wrote:
>
> On Mar 19, 2007, at 12:43 PM, Worky Workerson wrote:
> > 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.
...
> 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
This topic is locked and can not be replied to.