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

On 9/5/06, Andre N. [email protected] wrote:

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 N. [email protected] wrote:

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.

You probably can call Socket.for_fd using rb_funcall.

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

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

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

Hi!

On Wed, 2006-09-06 at 01:17 +0900, Kent S. 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

On 9/5/06, Andre N. [email protected] wrote:

extension. Any hints on how to do that?
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.

Hi,

2006/9/6, Francis C. [email protected]:

On 9/5/06, Andre N. [email protected] wrote:

On Wed, 2006-09-06 at 01:17 +0900, Kent S. wrote:
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.

Hi,

At Wed, 6 Sep 2006 20:41:41 +0900,
Andre N. 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.

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

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

[email protected] wrote:

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…

On 9/6/06, Nobuyoshi N. [email protected] 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.

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

Hi,

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

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

e$B$^$D$b$He(B e$B$f$-$R$m$G$9e(B

In message “Re: [ruby-dev:29523] reentr to Init_extension (Re: C socket
to Ruby socket)”

|At Thu, 7 Sep 2006 12:54:01 +0900,
|Nobuyoshi N. wrote in [ruby-talk:213070]:
|> This is a script to generate autoloading code.
|
|e$B$3$l$G5$IU$$$?$s$G$9$,!"<!$N$h$&$K$9$k$HBgNL$N7Y9p$,=P$^$9!#e(B
|
|$ ruby -e ‘m=“socket”;%w[BasicSocket Socket].each{|n|autoload(n, m)}’ -e Socket
|
|e$B3HD%%i%$%V%i%j$KBP$7$F$b%m!<%ICf$+$I$&$+$N%A%’%C%/$OI,MW$8$c$Je(B
|e$B$$$G$7$g$&$+!#e(B

e$B%3%_%C%H$7$F$/$@$5$$!#e(B

e$B$J$+$@$G$9!#e(B

At Thu, 7 Sep 2006 12:54:01 +0900,
Nobuyoshi N. wrote in [ruby-talk:213070]:

This is a script to generate autoloading code.

e$B$3$l$G5$IU$$$?$s$G$9$,!"<!$N$h$&$K$9$k$HBgNL$N7Y9p$,=P$^$9!#e(B

$ ruby -e ‘m=“socket”;%w[BasicSocket Socket].each{|n|autoload(n, m)}’ -e
Socket

e$B3HD%%i%$%V%i%j$KBP$7$F$b%m!<%ICf$+$I$&$+$N%A%’%C%/$OI,MW$8$c$Je(B
e$B$$$G$7$g$&$+!#e(B

Index: eval.c

RCS file: /cvs/ruby/src/ruby/eval.c,v
retrieving revision 1.944
diff -p -U 2 -r1.944 eval.c
— eval.c 4 Sep 2006 05:46:46 -0000 1.944
+++ eval.c 7 Sep 2006 23:41:08 -0000
@@ -7069,13 +7069,13 @@ rb_require_safe(VALUE fname, int safe)
else {
ruby_safe_level = 0;

  •   /* loading ruby library should be serialized. */
    
  •   if (!loading_tbl) {
    
  •       loading_tbl = st_init_strtable();
    
  •   }
    
  •   /* partial state */
    
  •   ftptr = ruby_strdup(RSTRING_PTR(path));
    
  •   st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread);
      switch (found) {
        case 'r':
    
  •       /* loading ruby library should be serialized. */
    
  •       if (!loading_tbl) {
    
  •   	loading_tbl = st_init_strtable();
    
  •       }
    
  •       /* partial state */
    
  •       ftptr = ruby_strdup(RSTRING_PTR(path));
    
  •       st_insert(loading_tbl, (st_data_t)ftptr, (st_data_t)curr_thread);
          rb_load(path, 0);
          break;