lib/ionian/extension/socket.rb in ionian-0.4.1 vs lib/ionian/extension/socket.rb in ionian-0.5.0

- old
+ new

@@ -1,7 +1,8 @@ require 'ionian/extension/io' require 'socket' +require 'ipaddr' module Ionian module Extension # A mixin for Socket objects. # @@ -21,22 +22,225 @@ # Initialize the Ionian Socket variables. # This is called automatically if #extend is called on an object. def initialize_ionian_socket end - # Returns true if the TCP_NODELAY flag is enabled (Nagle disabled). - # Otherwise false. + # Returns true if local address reuse is allowed. + # ( SO_REUSEADDR ) + def reuse_addr + param = self.getsockopt(::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR) + .data.unpack('i').first + param > 0 ? true : false + end + + alias_method :reuse_addr?, :reuse_addr + + # Allows local address reuse if true. + # ( SO_REUSEADDR ) + def reuse_addr=(value) + param = value ? 1 : 0 + self.setsockopt ::Socket::SOL_SOCKET, ::Socket::SO_REUSEADDR, [param].pack('i') + end + + # Returns the time to live (hop limit). + # ( IP_TTL ) + def ttl + self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_TTL) + .data.unpack('i').first + end + + alias_method :ttl?, :ttl + + # Sets the time to live (hop limit). + # ( IP_TTL ) + def ttl=(value) + self.setsockopt ::Socket::IPPROTO_IP, ::Socket::IP_TTL, [value].pack('i') + end + + # Returns true if the Nagle algorithm is disabled. + # ( TCP_NODELAY ) def no_delay - nagle_disabled = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY).data.ord - nagle_disabled > 0 ? true : false + param = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY) + .data.unpack('i').first + param > 0 ? true : false end - # Setting to true enables the TCP_NODELAY flag (disables Nagle). - # Setting to false disables the flag (enables Nagle). + alias_method :no_delay?, :no_delay + + # Disables the Nagle algorithm if true. + # ( TCP_NODELAY ) def no_delay=(value) - disable_nagle = value ? 1 : 0 - self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, disable_nagle + param = value ? 1 : 0 + self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_NODELAY, [param].pack('i') end + + # Returns true if multiple writes are buffered into a single segment. + # See #recork. + # Linux only. + # ( TCP_CORK ) + def cork + param = self.getsockopt(::Socket::IPPROTO_TCP, ::Socket::TCP_CORK) + .data.unpack('i').first + param > 0 ? true : false + end + + alias_method :cork?, :cork + + # Buffers multiple writes into a single segment if true. + # The segment is sent once the cork flag is disabled, + # the upper limit on the size of a segment is reached, + # the socket is closed, or 200ms elapses from the time + # the first corked byte is written. + # See #recork. + # Linux only. + # ( TCP_CORK ) + def cork=(value) + param = value ? 1 : 0 + self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_CORK, [param].pack('i') + end + + # Unsets cork to transmit data, then reapplies cork. + # ( TCP_CORK ) + def recork + self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_CORK, [0].pack('i') + self.setsockopt ::Socket::IPPROTO_TCP, ::Socket::TCP_CORK, [1].pack('i') + end + + # Join a multicast group. + # Address is the class D multicast address (uses remote + # address if not specified). + # Interface is the local network interface to receive the + # multicast traffic on (all interfaces if not specified). + # ( IP_ADD_MEMBERSHIP ) + def ip_add_membership(address = nil, interface = nil) + address ||= self.remote_address.ip_address + interface ||= '0.0.0.0' + + self.setsockopt \ + ::Socket::IPPROTO_IP, + ::Socket::IP_ADD_MEMBERSHIP, + IPAddr.new(address).hton + IPAddr.new(interface).hton + end + + # Leave a multicast group. + # Address is the class D multicast address (uses remote + # address if not specified). + # Interface is the local network interface the multicast + # traffic is received on (all interfaces if not specified). + # ( IP_DROP_MEMBERSHIP ) + def ip_drop_membership(address = nil, interface = nil) + address ||= self.remote_address.ip_address + interface ||= '0.0.0.0' + + self.setsockopt \ + ::Socket::IPPROTO_IP, + ::Socket::IP_DROP_MEMBERSHIP, + IPAddr.new(address).hton + IPAddr.new(interface).hton + end + + # Returns the default interface for outgoing multicasts. + # ( IP_MULTICAST_IF ) + def ip_multicast_if + self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_IF) + .data.unpack('CCCC').join('.') + end + + # Specify default interface for outgoing multicasts. + # ( IP_MULTICAST_IF ) + def ip_multicast_if=(interface = nil) + interface ||= '0.0.0.0' + + self.setsockopt \ + ::Socket::IPPROTO_IP, + ::Socket::IP_MULTICAST_IF, + IPAddr.new(interface).hton + end + + # Returns the time to live (hop limit) for outgoing multicasts. + # ( IP_MULTICAST_TTL ) + def ip_multicast_ttl + self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_TTL) + .data.unpack('C').first + end + + # Set the time to live (hop limit) for outgoing multicasts. + # ( IP_MULTICAST_TTL ) + def ip_multicast_ttl=(value) + self.setsockopt ::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_TTL, [value].pack('C') + end + + # Returns true if loopback of outgoing multicasts is enabled. + # ( IP_MULTICAST_LOOP ) + def ip_multicast_loop + param = self.getsockopt(::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_LOOP) + .data.unpack('C').first + param > 0 ? true : false + end + + alias_method :ip_multicast_loop?, :ip_multicast_loop + + # Enables loopback of outgoing multicasts if true. + # ( IP_MULTICAST_LOOP ) + def ip_multicast_loop=(value) + param = value ? 1 : 0 + self.setsockopt ::Socket::IPPROTO_IP, ::Socket::IP_MULTICAST_LOOP, [param].pack('C') + end + + def ipv6_add_membership + # TODO: Implement + false + end + + def ipv6_drop_membership + # TODO: Implement + false + end + + def ipv6_multicast_if + # TODO: Implement + false + end + + def ipv6_multicast_if=(value) + # TODO: Implement + end + + def ipv6_multicast_hops + # TODO: Implement + false + end + + def ipv6_multicast_hops=(value) + # TODO: Implement + end + + def ipv6_multicast_loop + # TODO: Implement + false + end + + alias_method :ipv6_multicast_loop?, :ipv6_multicast_loop + + def ipv6_multicast_loop=(value) + # TODO: Implement + end + + + class << self + # Returns true if the given address is within the multicast range. + def multicast(address) + address >= '224.0.0.0' and address <= '239.255.255.255' ? true : false + end + + alias_method :multicast?, :multicast + end + + # Returns true if the socket's address is in the multicast range. + def multicast + Ionian::Extension::Socket.multicast self.remote_address.ip_address + end + + alias_method :multicast?, :multicast end end end \ No newline at end of file