Subject:
[ruby-ffi] Correct type for binary buffer in a String?
From:
candlerb
Date:
5/5/11 7:44 AM
To:
ruby-ffi

Hi, I'm just getting started with FFI. I'd like to check what's the
right type to use when passing a String as a binary buffer. The
following code doesn't work:

# (1) built-in way
require 'socket'
s = Socket.new(Socket::AF_INET, Socket::SOCK_DGRAM, 0)
p s.getsockopt(Socket::IPPROTO_IP, Socket::IP_TTL)

# (2) FFI way
require 'ffi'

module Foo
  extend FFI::Library
  ffi_lib 'c'
  attach_function :getsockopt,
[:int, :int, :int, :buffer_inout, :size_t], :int
end

buf = "xxxxxxxx"
puts Foo.getsockopt(s.fileno, Socket::IPPROTO_IP, Socket::IP_TTL, buf,
buf.bytesize)  ## NOPE
p buf

The FFI getsockopt call is returning -1, and the buffer is unchanged.
(Supplementary question: how do I get at 'errno' in this case?)

It's the same if I use :string or :pointer instead of :buffer_inout.

Clearly this particular getsockopt call doesn't need a buffer_inout,
but there are cases where getsockopt *does* receive data and return
results in the same buffer, and ruby's built-in getsockopt doesn't
support this - http://redmine.ruby-lang.org/issues/4645

Specifically I'm looking at iptables. Sample code from the iptables
utility is below.

Many thanks,

Brian.

---- libiptc/libiptc.c ----

TC_INIT(const char *tablename)
{
...
        sockfd = socket(TC_AF, SOCK_RAW, IPPROTO_RAW);
        if (sockfd < 0)
                return NULL;

retry:
        s = sizeof(info);

        strcpy(info.name, tablename);
        if (getsockopt(sockfd, TC_IPPROTO, SO_GET_INFO, &info, &s) <
0) {
                close(sockfd);
                return NULL;
        }

        DEBUGP("valid_hooks=0x%08x, num_entries=%u, size=%u\n",
                info.valid_hooks, info.num_entries, info.size);