class Socket < BasicSocket class Option attr_reader :family, :level, :optname, :data def self.bool(family, level, optname, bool) new(family, level, optname, [bool ? 1 : 0].pack('i')) end def self.int(family, level, optname, integer) new(family, level, optname, [integer].pack('i')) end def self.linger(onoff, secs) linger = RubySL::Socket::Foreign::Linger.new begin linger.on_off = onoff linger.linger = secs new(:UNSPEC, :SOCKET, :LINGER, linger.to_s) ensure linger.free end end def initialize(family, level, optname, data) @family = RubySL::Socket.address_family(family) @level = RubySL::Socket::SocketOptions.socket_level(level, @family) @optname = RubySL::Socket::SocketOptions.socket_option(@level, optname) @data = data end def unpack(template) @data.unpack template end def inspect "#<#{self.class}: #@family_name #@level_name #@opt_name #{@data.inspect}>" end def bool expected_size = RubySL::Socket::Foreign::SIZEOF_INT unless @data.bytesize == expected_size raise TypeError, "invalid size, expected #{expected_size} but got #{@data.bytesize}" end if @data.unpack('i')[0] > 0 true else false end end def int expected_size = RubySL::Socket::Foreign::SIZEOF_INT unless @data.bytesize == expected_size raise TypeError, "invalid size, expected #{expected_size} but got #{@data.bytesize}" end @data.unpack('i')[0] end def linger if @level != Socket::SOL_SOCKET || @optname != Socket::SO_LINGER raise TypeError, 'linger socket option expected' end expected_size = RubySL::Socket::Foreign::Linger.size if @data.bytesize != expected_size raise TypeError, "invalid size, expected #{expected_size} but got #{@data.bytesize}" end linger = RubySL::Socket::Foreign::Linger.from_string(@data) onoff = nil case linger.on_off when 0 onoff = false when 1 onoff = true else onoff = linger.onoff.to_i end [onoff, linger.linger] end alias :to_s :data end end