Subject:
Re: [ruby-ffi] Unable to detect failure with reentrant function on Linux
From:
Wayne Meissner
Date:
6/12/10 10:24 PM
To:
ruby-ffi@googlegroups.com

A couple of things:
1) You should map getprotobynumber_r as:

attach_function 'getprotobynumber_r', [:int, :pointer, :pointer,
:long, :pointer], :int

2) and call it like so:


# getprotobynumber_r will use the buffer you pass in as the allocation
area for the names
# of the protocol, so allocate some native memory for it.

namebuf  = FFI::MemoryPointer.new(:char, 1024, false)
pstruct = ProtocolStruct.new
ptr = FFI::MemoryPointer.new(:pointer)

rc = getprotobynumber_r(protocol, pstruct, namebuf, 1024, qptr)

3) a return val of 0 signifies success, and pstruct will be filled out
with the data.  For non-zero returns, you should probably check errno,
and raise an exception if it is anything other than the not-found
case.

return rc == 0 && !qptr.get_pointer(0).null? ? pstruct[:p_name] : nil

Note: the signature for getprotobynumber_r is different across linux,
solaris and aix, so its a bit nasty, unless you only care about linux,
or you have code for each of those cases.


On 13 June 2010 12:38, Daniel Berger <djberg96@gmail.com> wrote:
> Hi,
>
> Ruby 1.8.6
> FFI 0.6.3
>
> I cannot seem to detect a failure with getprotobynumber_r on Linux
> when I intentionally pass it a bogus value. Instead, it returns the
> last value of /etc/protocols.
>
> What am I doing wrong?
>
> require 'ffi'
>
> module Net
>  class Proto
>    extend FFI::Library
>
>    unless RUBY_PLATFORM == 'java' && JRUBY_VERSION.to_f < 1.5
>      ffi_lib(FFI::Library::LIBC)
>    end
>
>    class ProtocolStruct < FFI::Struct
>      layout(
>        :p_name,    :string,
>        :p_aliases, :pointer,
>        :p_proto,   :int
>      )
>    end
>
>    attach_function 'setprotoent', [:int], :void
>    attach_function 'endprotoent', [], :void
>    attach_function 'getprotobynumber_r',
> [:int, :pointer, :string, :long, :pointer], :int
>
>    def self.getprotobynumber(protocol)
>      raise TypeError unless protocol.is_a?(Integer)
>
>      pptr = FFI::MemoryPointer.new(ProtocolStruct.size)
>      qptr = FFI::MemoryPointer.new(ProtocolStruct.size)
>      buf  = 1.chr * 1024
>
>      begin
>        setprotoent(0)
>        int = getprotobynumber_r(protocol, pptr, buf, buf.size, qptr)
>      ensure
>        endprotoent()
>      end
>
>      int > 0 || qptr.null? ? nil : ProtocolStruct.new(pptr)[:p_name]
>    end
>  end
> end
>
> p Net::Proto.getprotobynumber(999999999) # should be nil
>
> Regards,
>
> Dan