class Pione::Notification::Receiver

‘Notification::Receiver` provides the function to receive notification packets. Be careful we assume notification’s packet is small.

Constants

LOCK

a lock for receiving notifications

MAX_SIZE

Public Class Methods

new(uri) click to toggle source

@param uri [URI]

URI of receiver address
# File lib/pione/notification/receiver.rb, line 13
def initialize(uri)
  unless ["pnb", "pnm", "pnu"].include?(uri.scheme)
    raise ArgumentError.new(uri)
  end

  @uri = uri
  open
end

Public Instance Methods

close() click to toggle source

Close the receiver socket.

# File lib/pione/notification/receiver.rb, line 41
def close
  @socket.close
end
closed?() click to toggle source

Return true if receiver socket is closed.

@return [Boolean]

true if receiver socket is closed
# File lib/pione/notification/receiver.rb, line 49
def closed?
  @socket.closed?
end
receive() click to toggle source

Receive a notification packet.

# File lib/pione/notification/receiver.rb, line 23
def receive
  data, addr = LOCK.synchronize {@socket.recvfrom(MAX_SIZE)}
  ip_address = addr[3]
  message = Message.load(data)
  return [ip_address, message]
rescue TypeError, NoMethodError
  ip_address = ip_address || "(unknown)"
  Log::Debug.notification("Invalid data has been received from %s." % ip_address)
  retry
end
reopen() click to toggle source

Close and open receiver socket.

# File lib/pione/notification/receiver.rb, line 35
def reopen
  close
  open(@host, @port)
end

Private Instance Methods

open() click to toggle source

Open a receiver socket with the port number. Be careful that Linux seems to require INADDR_ANY to receive broadcast packets, and Windows seems not to require.

@return [void]

# File lib/pione/notification/receiver.rb, line 60
def open
  _host = IPSocket.getaddress(@uri.host)

  @socket = UDPSocket.open
  @socket.bind(_host, @uri.port)

  case @uri.scheme
  when "pnb"
    unless not(OS.windows?) and IPAddr.new(_host) == Socket::INADDR_ANY
      msg = [
        "Notification receiver address %p is not INADDR_ANY(%p), ",
        "this may cause to fail receiving broadcast packets. ",
        "If you can receive it, please tell me your platform name."
      ].join
      Log::SystemLog.warn(msg % [@uri.host, "0.0.0.0"])
    end

    @socket.setsockopt(Socket::SOL_SOCKET, Socket::SO_BROADCAST, 1)
  when "pnm"
    group = IPAddr.new(@uri.host).hton
    if @uri.interface
      interface = IPAddr.new(@uri.interface).hton
    else
      interface = IPAddr.new(Addrinfo.ip(Socket::INADDR_ANY).ip_address).hton
    end
    @socket.setsockopt(Socket::IPPROTO_IP, Socket::IP_ADD_MEMBERSHIP, group + interface)
  end
end