Implement sendmsg/recvmsg for 1.8 using ffi

This commit is contained in:
Brian Candler
2011-05-06 13:41:42 +01:00
parent bce9d81377
commit da2db43c8a
2 changed files with 83 additions and 1 deletions

View File

@@ -2,6 +2,7 @@ require 'socket'
require 'linux/constants'
require 'linux/error'
require 'linux/netlink/message'
require 'linux/sendmsg'
module Linux
module Netlink
@@ -194,7 +195,8 @@ module Netlink
if select([@socket], nil, nil, timeout)
mesg, sender, rflags, controls = @socket.recvmsg
raise EOFError unless mesg
NLSocket.check_sockaddr(sender.to_sockaddr)
sender = sender.to_sockaddr if sender.respond_to? :to_sockaddr
NLSocket.check_sockaddr(sender)
mesg
else
raise "Timeout"

80
lib/linux/sendmsg.rb Normal file
View File

@@ -0,0 +1,80 @@
# Patchup to add Socket#sendmsg and Socket#recvmsg for ruby 1.8
if BasicSocket.instance_methods.grep(/^sendmsg$/).empty?
require 'ffi'
class BasicSocket
module FFIExt
extend FFI::Library
ffi_lib FFI::Library::LIBC
attach_function :sendmsg, [:int, :buffer_in, :int], :ssize_t
attach_function :recvmsg, [:int, :buffer_inout, :int], :ssize_t
end
class Msghdr < FFI::Struct
layout :name, :pointer,
:namelen, :socklen_t,
:iov, :pointer,
:iovlen, :size_t,
:control, :pointer,
:controllen, :socklen_t,
:flags, :int
end
class IOVec < FFI::Struct
layout :base, :pointer,
:len, :size_t
end
def sendmsg(mesg, flags=0, dest_sockaddr=nil, *controls)
data = FFI::MemoryPointer.new(mesg.bytesize, 1, false)
data.put_bytes(0, mesg)
iov = IOVec.new
iov[:base] = data
iov[:len] = mesg.bytesize
header = Msghdr.new
header[:name] = nil # TODO: dest_sockaddr
header[:namelen] = 0 # dest_sockaddr
header[:iov] = iov
header[:iovlen] = 1
header[:control] = nil # TODO: controls
header[:controllen] = 0 # controls
header[:flags] = flags
Kernel.select(nil, [self])
res = FFIExt.sendmsg(fileno, header, flags)
raise "sendmsg error: #{res}" if res < 0 # FIXME: read errno
# return numbytes_sent
res
end
def recvmsg(maxmesglen=nil, flags=0, maxcontrollen=nil, opts={})
data = FFI::MemoryPointer.new(maxmesglen || 4096, 1, false)
namebuf = FFI::MemoryPointer.new(64, 1, false)
iov = IOVec.new
iov[:base] = data
iov[:len] = data.size
header = Msghdr.new
header[:name] = namebuf
header[:namelen] = namebuf.size
header[:iov] = iov
header[:iovlen] = 1
header[:flags] = flags
Kernel.select([self])
res = FFIExt.recvmsg(fileno, header, flags)
raise "recvmsg error: #{res}" if res < 0 # FIXME: read errno
# return [mesg, sender_addrinfo, rflags, *controls]
return [
data.get_bytes(0, res),
namebuf.get_bytes(0, header[:namelen]),
header[:flags]
# TODO: controls
]
end
end
end