C socket to Ruby socket

Hello

What is the correct way to convert a C socket (int) to a Ruby Socket
object in a C extension? Something like

  int s = socket(...);
  VALUE sock = rb_some_func(s);

In my extension there's a callback function that receives a socket as an
argument, and I'd like to pass that socket as an argument to a ruby
block, so I need to convert it to a Socket object first.

Thanks in advance,
Andre

does it need to be a Socket? class IO can be initialized with a file descriptor.

···

On 9/5/06, Andre Nathan <andre@digirati.com.br> wrote:

Hello

What is the correct way to convert a C socket (int) to a Ruby Socket
object in a C extension? Something like

  int s = socket(...);
  VALUE sock = rb_some_func(s);

In my extension there's a callback function that receives a socket as an
argument, and I'd like to pass that socket as an argument to a ruby
block, so I need to convert it to a Socket object first.

Thanks in advance,
Andre

You probably can call Socket.for_fd using rb_funcall.

···

On 9/5/06, Andre Nathan <andre@digirati.com.br> wrote:

Hello

What is the correct way to convert a C socket (int) to a Ruby Socket
object in a C extension? Something like

  int s = socket(...);
  VALUE sock = rb_some_func(s);

In my extension there's a callback function that receives a socket as an
argument, and I'd like to pass that socket as an argument to a ruby
block, so I need to convert it to a Socket object first.

--
Kent
---

You mean rb_io_initialize()?

It would be nice if it was a socket, and even better if there was a way
to find out if it is a TCPSocket or a UDPSocket, since it's always a
network connection (no UNIXSocket, for example).

Thanks,
Andre

···

On Wed, 2006-09-06 at 01:02 +0900, Francis Cianfrocca wrote:

does it need to be a Socket? class IO can be initialized with a file descriptor.

Hi!

···

On Wed, 2006-09-06 at 01:17 +0900, Kent Sibilev wrote:

You probably can call Socket.for_fd using rb_funcall.

I got it to work with an IO:

  rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2NUM(socket));

However I can't seem to be able to make rb_cSocket visible to my
extension. Any hints on how to do that?

Thanks,
Andre

You may find this unacceptably ugly, but how about:

char buf[100];
snprintf (buf, sizeof(buf)-1, "Socket.for_fd( %d )", socket);
rb_eval_string (buf);

There was some radio chatter on the core list a few months back about
the fact that rb_cSocket is not externed in ruby.h. As I recall the
omission is an oversight, not something fundamental. You could also
say

extern VALUE rb_cSocket;

in your extension. I've done that before.

···

On 9/5/06, Andre Nathan <andre@digirati.com.br> wrote:

Hi!

On Wed, 2006-09-06 at 01:17 +0900, Kent Sibilev wrote:
> You probably can call Socket.for_fd using rb_funcall.

I got it to work with an IO:

  rb_funcall(rb_cIO, rb_intern("for_fd"), 1, INT2NUM(socket));

However I can't seem to be able to make rb_cSocket visible to my
extension. Any hints on how to do that?

Hi,

> However I can't seem to be able to make rb_cSocket visible to my
> extension. Any hints on how to do that?

rb_const_get(rb_cObject, rb_intern("TCPSocket"));

There was some radio chatter on the core list a few months back about
the fact that rb_cSocket is not externed in ruby.h. As I recall the
omission is an oversight, not something fundamental. You could also
say

extern VALUE rb_cSocket;

in your extension. I've done that before.

It doesn't work always on all platforms.

···

2006/9/6, Francis Cianfrocca <garbagecat10@gmail.com>:

On 9/5/06, Andre Nathan <andre@digirati.com.br> wrote:
> On Wed, 2006-09-06 at 01:17 +0900, Kent Sibilev wrote:

--
Nobu Nakada

rb_const_get(rb_cObject, rb_intern("TCPSocket"));

That worked, thanks!

> extern VALUE rb_cSocket;
>
> in your extension. I've done that before.

It doesn't work always on all platforms.

Will it eventually be externed in ruby.h then?

Thanks,
Andre

···

On Wed, 2006-09-06 at 12:49 +0900, Nobuyoshi Nakada wrote:

Hi,

At Wed, 6 Sep 2006 20:41:41 +0900,
Andre Nathan wrote in [ruby-talk:212933]:

> > extern VALUE rb_cSocket;
> >
> > in your extension. I've done that before.
>
> It doesn't work always on all platforms.

Will it eventually be externed in ruby.h then?

It isn't the point. Dynamically loaded symbols may not visible
from other loaded libraries.

···

--
Nobu Nakada

nobu@ruby-lang.org wrote:

Hi,

At Wed, 6 Sep 2006 20:41:41 +0900,
Andre Nathan wrote in [ruby-talk:212933]:

extern VALUE rb_cSocket;

in your extension. I've done that before.

It doesn't work always on all platforms.

Will it eventually be externed in ruby.h then?

It isn't the point. Dynamically loaded symbols may not visible
from other loaded libraries.

Socket is a pretty popular library. Maybe rb_cSocket could be declared in IO.c?

just a thought, and it would be inelegant...

···

--
       vjoel : Joel VanderWerf : path berkeley edu : 510 665 3407

Hi,

At Thu, 7 Sep 2006 05:04:12 +0900,
Joel VanderWerf wrote in [ruby-talk:213012]:

>>>> extern VALUE rb_cSocket;
>>>>
>>>> in your extension. I've done that before.
>>> It doesn't work always on all platforms.
>> Will it eventually be externed in ruby.h then?
>
> It isn't the point. Dynamically loaded symbols may not visible
> from other loaded libraries.
>

Socket is a pretty popular library. Maybe rb_cSocket could be declared
in IO.c?

It would be popular indeed, but is an extension library, which may or
may not be loaded. By just accessing, it can be zero if it hasn't
been loaded yet. So you need to ensure it got loaded:

    rb_require("socket");
    rb_funcall(rb_cTCPSocket, rb_intern("for_fd"), 1, INT2NUM(socket));

I guess this might be better with autoloading.

    rb_funcall(rb_path2class("TCPSocket"), rb_intern("for_fd"), 1,
INT2NUM(socket));

This is a script to generate autoloading code.

#!./miniruby -s

Top = "rb_cObject"

class String
  if File::ALT_SEPARATOR
    def proppath
      tr!(File::ALT_SEPARATOR, File::SEPARATOR)
      self
    end
  else
    def proppath
      self
    end
  end
end
$srcdir.proppath if $srcdir

header = "ruby.h"
header = File.join($srcdir, header) if $srcdir
stdmod = {}
IO.foreach(header) do |line|
  if n = line[/^RUBY_EXTERN\s+VALUE\s+(rb_[mc]\w+);/, 1]
    stdmod[n] = true
  end
end

if ARGV.empty?
  ext = "ext"
  ext = File.join($srcdir, ext) if $srcdir
  dirs = [ext]
else
  dirs = ARGV.collect {|d| d.proppath}
end

if $srcdir
  srcpre = %r"\A#{Regexp.quote($srcdir)}/"
else
  srcpre = /\A/
end

dirs.collect! do |d|
  if File.basename(d) == "extconf.rb"
    d
  else
    Dir.glob(File.join(d, "**/extconf.rb"))
  end
end
dirs.flatten!
region = " /* begin autoload */"
dirs.each do |e|
  if File.directory?(e) and !File.exist?(e = File.join(e, "extconf.rb"))
    next
  end
  comment = "\n /* #{File.dirname(e.sub(srcpre, ''))} */"
  modname = IO.read(e)[/create_makefile\s*[\s\(]([\'\"])(.*?)\1\s*\)?/,
2] or next
  ARGV.replace(Dir.glob(File.join(File.dirname(e), "*.c")))
  ARGF.each do |line|
    /\brb_define_(?:class|module)(?:\s*\(|_under\s*\((\w+)\s*,)?\s*("\w+")/
=~ line or next
    name, mod = $2, $1
    if !mod
      mod = Top
    elsif !stdmod[mod]
      next
    end
    if comment
      if region
        puts region
        region = nil
      end
      puts comment
      comment = nil
    end
    puts " rb_autoload(#{mod}, rb_intern(#{name}), \"#{modname}\");"
  end
end
puts "\n /* end autoload */" unless region

···

--
Nobu Nakada

Nobu, thanks for clearing that up. Now I understand why the more
resolved socket classes are not externed by default.

···

On 9/6/06, Nobuyoshi Nakada <nobu@ruby-lang.org> wrote:
> It would be popular indeed, but is an extension library, which may or

may not be loaded. By just accessing, it can be zero if it hasn't
been loaded yet. So you need to ensure it got loaded:

    rb_require("socket");
    rb_funcall(rb_cTCPSocket, rb_intern("for_fd"), 1, INT2NUM(socket));

I guess this might be better with autoloading.