-
-
Save yorickpeterse/aab6902a604ac34a519a to your computer and use it in GitHub Desktop.
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
class Socket < BasicSocket | |
class AncillaryData | |
LEVEL_PREFIXES = { | |
Socket::SOL_SOCKET => %w{SCM_ UNIX}, | |
Socket::IPPROTO_IP => %w{IP_ IP}, | |
Socket::IPPROTO_IPV6 => %w{IPV6_ IPV6}, | |
Socket::IPPROTO_TCP => %w{TCP_ TCP}, | |
Socket::IPPROTO_UDP => %w{UDP_ UDP} | |
} | |
attr_reader :family, :level, :type, :data | |
def initialize(family, level, type, data) | |
@family = RubySL::Socket::Helpers.address_family(family) | |
@data = RubySL::Socket::Helpers.coerce_to_string(data) | |
if level.is_a?(Fixnum) | |
@level = level | |
else | |
level = RubySL::Socket::Helpers.coerce_to_string(level) | |
if level == 'SOL_SOCKET' or level == 'SOCKET' | |
@level = Socket::SOL_SOCKET | |
else | |
prefixed = RubySL::Socket::Helpers.prefix_with(level, 'IPPROTO_') | |
@level = RubySL::Socket::Helpers.socket_constant(prefixed) do | |
"unknown protocol level: #{level}" | |
end | |
end | |
end | |
if type.is_a?(Fixnum) | |
@type = type | |
else | |
type = RubySL::Socket::Helpers.coerce_to_string(type) | |
if @family == Socket::AF_INET or @family == Socket::AF_INET6 | |
prefix, label = LEVEL_PREFIXES[@level] | |
else | |
prefix, label = LEVEL_PREFIXES[Socket::SOL_SOCKET] | |
end | |
if prefix and label | |
prefixed = RubySL::Socket::Helpers.prefix_with(type, prefix) | |
@type = RubySL::Socket::Helpers.socket_constant(prefixed) do | |
"Unknown #{label} control message: #{type}" | |
end | |
else | |
raise TypeError, "no implicit conversion of #{type.class} into Integer" | |
end | |
end | |
end | |
end | |
end |
This file contains bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
require 'socket' | |
describe 'Socket::AncillaryData#initialize' do | |
describe 'using Fixnums for the family, level, and type' do | |
before do | |
@data = Socket::AncillaryData | |
.new(Socket::AF_INET, Socket::IPPROTO_IP, Socket::IP_RECVTTL, 'ugh') | |
end | |
it 'sets the address family' do | |
@data.family.should == Socket::AF_INET | |
end | |
it 'sets the message level' do | |
@data.level.should == Socket::IPPROTO_IP | |
end | |
it 'sets the message type' do | |
@data.type.should == Socket::IP_RECVTTL | |
end | |
it 'sets the data' do | |
@data.data.should == 'ugh' | |
end | |
end | |
describe 'using Symbols for the family, level, and type' do | |
before do | |
@data = Socket::AncillaryData.new(:INET, :IPPROTO_IP, :RECVTTL, 'ugh') | |
end | |
it 'sets the address family' do | |
@data.family.should == Socket::AF_INET | |
end | |
it 'sets the message level' do | |
@data.level.should == Socket::IPPROTO_IP | |
end | |
it 'sets the message type' do | |
@data.type.should == Socket::IP_RECVTTL | |
end | |
it 'sets the data' do | |
@data.data.should == 'ugh' | |
end | |
end | |
describe 'using Strings for the family, level, and type' do | |
before do | |
@data = Socket::AncillaryData.new('INET', 'IPPROTO_IP', 'RECVTTL', 'ugh') | |
end | |
it 'sets the address family' do | |
@data.family.should == Socket::AF_INET | |
end | |
it 'sets the message level' do | |
@data.level.should == Socket::IPPROTO_IP | |
end | |
it 'sets the message type' do | |
@data.type.should == Socket::IP_RECVTTL | |
end | |
it 'sets the data' do | |
@data.data.should == 'ugh' | |
end | |
end | |
describe 'using custom objects with a to_str method for the family, level, and type' do | |
before do | |
fmock = mock(:family) | |
lmock = mock(:level) | |
tmock = mock(:type) | |
dmock = mock(:data) | |
fmock.stub!(:to_str).and_return('INET') | |
lmock.stub!(:to_str).and_return('IP') | |
tmock.stub!(:to_str).and_return('RECVTTL') | |
dmock.stub!(:to_str).and_return('ugh') | |
@data = Socket::AncillaryData.new(fmock, lmock, tmock, dmock) | |
end | |
it 'sets the address family' do | |
@data.family.should == Socket::AF_INET | |
end | |
it 'sets the message level' do | |
@data.level.should == Socket::IPPROTO_IP | |
end | |
it 'sets the message type' do | |
@data.type.should == Socket::IP_RECVTTL | |
end | |
it 'sets the data' do | |
@data.data.should == 'ugh' | |
end | |
end | |
describe 'using :AF_INET as the family and :SOCKET as the level' do | |
it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do | |
Socket::AncillaryData.new(:INET, :SOCKET, :RIGHTS, '').type | |
.should == Socket::SCM_RIGHTS | |
end | |
it 'sets the type to SCM_TIMESTAMP when using :TIMESTAMP as the type argument' do | |
Socket::AncillaryData.new(:INET, :SOCKET, :TIMESTAMP, '').type | |
.should == Socket::SCM_TIMESTAMP | |
end | |
it 'raises TypeError when using a numeric string as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :IGMP, Socket::SCM_RIGHTS.to_s, '') } | |
.should raise_error(TypeError) | |
end | |
it 'raises SocketError when using :RECVTTL as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :SOCKET, :RECVTTL, '') } | |
.should raise_error(SocketError) | |
end | |
it 'raises SocketError when using :MOO as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :SOCKET, :MOO, '') } | |
.should raise_error(SocketError) | |
end | |
it 'raises SocketError when using :IP_RECVTTL as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :SOCKET, :IP_RECVTTL, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_INET as the family and :ICMP as the level' do | |
it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do | |
Socket::AncillaryData.new(:INET, :ICMP, :RIGHTS, '').type | |
.should == Socket::SCM_RIGHTS | |
end | |
end | |
describe 'using :AF_INET as the family and :IP as the level' do | |
it 'sets the type to IP_RECVTTL when using :RECVTTL as the type argument' do | |
Socket::AncillaryData.new(:INET, :IP, :RECVTTL, '').type | |
.should == Socket::IP_RECVTTL | |
end | |
it 'sets the type to IP_MTU when using :MTU as the type argument' do | |
Socket::AncillaryData.new(:INET, :IP, :MTU, '').type | |
.should == Socket::IP_MTU | |
end | |
it 'raises SocketError when using :RIGHTS as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :IP, :RIGHTS, '') } | |
.should raise_error(SocketError) | |
end | |
it 'raises SocketError when using :MOO as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :IP, :MOO, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_INET as the family and :IPV6 as the level' do | |
it 'sets the type to IPV6_CHECKSUM when using :CHECKSUM as the type argument' do | |
Socket::AncillaryData.new(:INET, :IPV6, :CHECKSUM, '').type | |
.should == Socket::IPV6_CHECKSUM | |
end | |
it 'sets the type to IPV6_NEXTHOP when using :NEXTHOP as the type argument' do | |
Socket::AncillaryData.new(:INET, :IPV6, :NEXTHOP, '').type | |
.should == Socket::IPV6_NEXTHOP | |
end | |
it 'raises SocketError when using :RIGHTS as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :IPV6, :RIGHTS, '') } | |
.should raise_error(SocketError) | |
end | |
it 'raises SocketError when using :MOO as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :IPV6, :MOO, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_INET as the family and :TCP as the level' do | |
it 'sets the type to TCP_CORK when using :CORK as the type argument' do | |
Socket::AncillaryData.new(:INET, :TCP, :CORK, '').type | |
.should == Socket::TCP_CORK | |
end | |
it 'sets the type to TCP_INFO when using :INFO as the type argument' do | |
Socket::AncillaryData.new(:INET, :TCP, :INFO, '').type | |
.should == Socket::TCP_INFO | |
end | |
it 'raises SocketError when using :RIGHTS as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :TCP, :RIGHTS, '') } | |
.should raise_error(SocketError) | |
end | |
it 'raises SocketError when using :MOO as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :TCP, :MOO, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_INET as the family and :UDP as the level' do | |
it 'sets the type to UDP_CORK when using :CORK as the type argument' do | |
Socket::AncillaryData.new(:INET, :UDP, :CORK, '').type | |
.should == Socket::UDP_CORK | |
end | |
it 'raises SocketError when using :RIGHTS as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :UDP, :RIGHTS, '') } | |
.should raise_error(SocketError) | |
end | |
it 'raises SocketError when using :MOO as the type argument' do | |
proc { Socket::AncillaryData.new(:INET, :UDP, :MOO, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_UNIX as the family and :SOCKET as the level' do | |
it 'sets the type to SCM_RIGHTS when using :RIGHTS as the type argument' do | |
Socket::AncillaryData.new(:UNIX, :SOCKET, :RIGHTS, '').type | |
.should == Socket::SCM_RIGHTS | |
end | |
it 'raises SocketError when using :CORK sa the type argument' do | |
proc { Socket::AncillaryData.new(:UNIX, :SOCKET, :CORK, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_UNIX as the family and :IP as the level' do | |
it 'raises SocketError' do | |
proc { Socket::AncillaryData.new(:UNIX, :IP, :RECVTTL, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_UNIX as the family and :IPV6 as the level' do | |
it 'raises SocketError' do | |
proc { Socket::AncillaryData.new(:UNIX, :IPV6, :NEXTHOP, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_UNIX as the family and :TCP as the level' do | |
it 'raises SocketError' do | |
proc { Socket::AncillaryData.new(:UNIX, :TCP, :CORK, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
describe 'using :AF_UNIX as the family and :UDP as the level' do | |
it 'raises SocketError' do | |
proc { Socket::AncillaryData.new(:UNIX, :UDP, :CORK, '') } | |
.should raise_error(SocketError) | |
end | |
end | |
end |
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment