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);