Class: Nl::Raw::Protocol

Inherits:
Object
  • Object
show all
Defined in:
nl/lib/nl/raw/protocol.rb

Overview

Socket-wide wire behavior for a classic (netlink-raw) protocol.

Direct Known Subclasses

Genl::Protocol

Instance Attribute Summary collapse

Instance Method Summary collapse

Constructor Details

#initialize(protonum) ⇒ Protocol

Returns a new instance of Protocol.



37
38
39
# File 'nl/lib/nl/raw/protocol.rb', line 37

def initialize(protonum)
  @protonum = protonum
end

Instance Attribute Details

#protonum ⇒ Object (readonly)

Returns the value of attribute protonum.



35
36
37
# File 'nl/lib/nl/raw/protocol.rb', line 35

def protonum
  @protonum
end

Instance Method Details

#build_request(endpoint, kind, request_class, args) ⇒ Object



87
88
89
90
91
92
93
# File 'nl/lib/nl/raw/protocol.rb', line 87

def build_request(endpoint, kind, request_class, args)
  flags = Raw::NLM_F_REQUEST
  flags |= kind == :dump ? Raw::NLM_F_DUMP : Raw::NLM_F_ACK

  message = request_class.from_params(args)
  Request.new(type: endpoint.frame_type(request_class), flags:, message:)
end

#decode_frame(_endpoint, header, payload, message_class) ⇒ Object

Decodes one frame using the reply class associated with its sequence.



50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
# File 'nl/lib/nl/raw/protocol.rb', line 50

def decode_frame(_endpoint, header, payload, message_class)
  decoder = Decoder.new(payload)
  if header.type < Raw::NLMSG_MIN_TYPE
    case header.type
    when Raw::NLMSG_ERROR
      errno = decoder.get_value(Endian::Host::SINT)
      if errno.positive?
        raise ProtocolViolation, "expected zero or negative NLMSG_ERROR errno, got #{errno}"
      end

      errno.zero? ? AckFrame.new(header:) : ErrorFrame.new(header:, errno: -errno)
    when Raw::NLMSG_DONE
      return DoneFrame.new(header:, errno: nil) unless decoder.available?

      errno = decoder.get_value(Endian::Host::SINT)
      if errno.positive?
        raise ProtocolViolation, "expected zero or negative NLMSG_DONE errno, got #{errno}"
      end

      DoneFrame.new(header:, errno: errno.negative? ? -errno : nil)
    else
      UnknownFrame.new(header:)
    end
  else
    raise ArgumentError, 'reply class is required for a data message' unless message_class

    DataFrame.new(header:, message: message_class.decode(decoder, type: header.type))
  end
end

#decode_notification(endpoint, header, payload, message_class) ⇒ Object



107
108
109
# File 'nl/lib/nl/raw/protocol.rb', line 107

def decode_notification(endpoint, header, payload, message_class)
  decode_frame(endpoint, header, payload, message_class).message
end

#encode_message(encoder, _endpoint, request, seq:, pid:) ⇒ Object



41
42
43
44
45
46
47
# File 'nl/lib/nl/raw/protocol.rb', line 41

def encode_message(encoder, _endpoint, request, seq:, pid:)
  header = Raw::NlMsgHdr.new(0, request.type, request.flags, seq, pid)
  encoder.measure(Endian::Host::U16) do
    header.encode(encoder)
    request.message.encode(encoder)
  end
end

#notification_channel_key(endpoint) ⇒ Object



95
# File 'nl/lib/nl/raw/protocol.rb', line 95

def notification_channel_key(endpoint) = endpoint.definition

#notification_class(_endpoint, header, _payload, classes) ⇒ Object



103
104
105
# File 'nl/lib/nl/raw/protocol.rb', line 103

def notification_class(_endpoint, header, _payload, classes)
  classes[header.type]
end

#notification_frame?(_endpoint, header, _payload) ⇒ Boolean

Returns:

  • (Boolean)


99
100
101
# File 'nl/lib/nl/raw/protocol.rb', line 99

def notification_frame?(_endpoint, header, _payload)
  header.type >= Raw::NLMSG_MIN_TYPE
end

#notification_frame_key(header) ⇒ Object



97
# File 'nl/lib/nl/raw/protocol.rb', line 97

def notification_frame_key(header) = header.type

#notification_route_keys(_endpoint, classes) ⇒ Object



96
# File 'nl/lib/nl/raw/protocol.rb', line 96

def notification_route_keys(_endpoint, classes) = classes.keys

#send_message(socket, endpoint, request, seq:, pid:) ⇒ Object



80
81
82
83
84
85
# File 'nl/lib/nl/raw/protocol.rb', line 80

def send_message(socket, endpoint, request, seq:, pid:)
  encoder = Encoder.new
  encode_message(encoder, endpoint, request, seq:, pid:)
  socket.sendmsg(encoder.buffer.get_string, 0, Socket.sockaddr_nl(0, 0))
  nil
end