Class: Cosmos::UdpWriteSocket

Inherits:
Object
  • Object
show all
Defined in:
lib/cosmos/io/udp_sockets.rb

Overview

Creates a UDPSocket and implements a non-blocking write.

Class Method Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(dest_address, dest_port, src_port = nil, interface_address = nil, ttl = 1, bind_address = "0.0.0.0") ⇒ UdpWriteSocket

Returns a new instance of UdpWriteSocket.

Parameters:

  • dest_address (String)

    Host to send data to

  • dest_port (Integer)

    Port to send data to

  • src_port (Integer[ Port to send data out from) (defaults to: nil)

    rc_port [Integer[ Port to send data out from

  • interface_address (String) (defaults to: nil)

    Local outgoing interface to send from

  • ttl (Integer) (defaults to: 1)

    Time To Live for outgoing packets



29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
# File 'lib/cosmos/io/udp_sockets.rb', line 29

def initialize(dest_address,
               dest_port,
               src_port = nil,
               interface_address = nil,
               ttl = 1,
               bind_address = "0.0.0.0")
  @socket = UDPSocket.new

  # Basic setup to reuse address
  @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_REUSEADDR, 1)

  # Set source port if given
  @socket.bind(bind_address, src_port) if src_port

  # Default send to the specified address and port
  @socket.connect(dest_address, dest_port)

  # Handle multicast
  if UdpWriteSocket.multicast?(dest_address)
    # Basic setup set time to live
    @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_TTL, ttl.to_i)

    # Set outgoing interface
    @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_MULTICAST_IF, IPAddr.new(interface_address).hton) if interface_address
  end
end

Dynamic Method Handling

This class handles dynamic methods through the method_missing method

#method_missing(method, *args, &block) ⇒ Object

Defer all methods to the UDPSocket



82
83
84
# File 'lib/cosmos/io/udp_sockets.rb', line 82

def method_missing(method, *args, &block)
  @socket.__send__(method, *args, &block)
end

Class Method Details

.multicast?(host) ⇒ Boolean

Returns Whether the hostname is multicast.

Parameters:

  • host (String)

    Machine name or IP address

Returns:

  • (Boolean)

    Whether the hostname is multicast



88
89
90
91
92
93
94
95
96
97
98
99
100
101
102
103
104
105
# File 'lib/cosmos/io/udp_sockets.rb', line 88

def self.multicast?(host)
  return false if host.nil?
  # Look up address
  _, _, _, *address_list = Socket.gethostbyname(host)
  first_addr_byte = 0
  address_list.each do |address|
    if address.length == 4
      first_addr_byte = address.getbyte(0)
      break
    end
  end

  if (first_addr_byte >= 224) && (first_addr_byte <= 239)
    true
  else
    false
  end
end

Instance Method Details

#write(data, write_timeout = 10.0) ⇒ Object

Parameters:

  • data (String)

    Binary data to send

  • write_timeout (Float) (defaults to: 10.0)

    Time in seconds to wait for the data to send



58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
# File 'lib/cosmos/io/udp_sockets.rb', line 58

def write(data, write_timeout = 10.0)
  num_bytes_to_send = data.length
  total_bytes_sent  = 0
  bytes_sent = 0
  data_to_send = data

  loop do
    begin
      bytes_sent = @socket.write_nonblock(data_to_send)
    rescue Errno::EAGAIN, Errno::EWOULDBLOCK
      result = IO.fast_select(nil, [@socket], nil, write_timeout)
      if result
        retry
      else
        raise Timeout::Error, "Write Timeout"
      end
    end
    total_bytes_sent += bytes_sent
    break if total_bytes_sent >= num_bytes_to_send
    data_to_send = data[total_bytes_sent..-1]
  end
end