Class: PacketGen::Types::AbstractTLV

Inherits:
Fields
  • Object
show all
Defined in:
lib/packetgen/types/abstract_tlv.rb

Overview

This class is an abstract class to define type-length-value data.

This class supersede TLV class, which is not well defined on some corner cases.

Usage

To simply define a new TLV class, do:

MyTLV = PacketGen::Types::AbstractTLV.create
MyTLV.define_type_enum 'one' => 1, 'two' => 2

This will define a new MyTLV class, subclass of Fields. This class will define 3 fields:

  • #type, as a Int8Enum by default,

  • #length, as a Int8 by default,

  • and #value, as a String by default.

.define_type_enum is, here, necessary to define enum hash to be used for #type accessor, as this one is defined as an Enum.

This class may then be used as older TLV class:

tlv = MyTLV.new(type: 1, value: 'abcd')  # automagically set #length from value
tlv.type        #=> 1
tlv.human_type  #=> 'one'
tlv.length      #=> 4
tlv.value       #=> "abcd"

Advanced usage

Each field’s type may be change at generating TLV class:

MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
                                             length_class: PacketGen::Types::Int16,
                                             value_class: PacketGen::Header::IP::Addr)
tlv = MyTLV.new(type: 1, value: '1.2.3.4')
tlv.type        #=> 1
tlv.length      #=> 4
tlv.value       #=> '1.2.3.4'
tlv.to_s        #=> "\x00\x01\x00\x04\x01\x02\x03\x04"

Some aliases may also be defined. For example, to create a TLV type whose type field should be named code:

MyTLV = PacketGen::Types::AbstractTLV.create(type_class: PacketGen::Types::Int16,
                                             length_class: PacketGen::Types::Int16,
                                             aliases: { code: :type })
tlv = MyTLV.new(code: 1, value: 'abcd')
tlv.code        #=> 1
tlv.type        #=> 1
tlv.length      #=> 4
tlv.value       #=> 'abcd'

Author:

  • Sylvain Daubert

Since:

Class Attribute Summary collapse

Instance Attribute Summary collapse

Class Method Summary collapse

Instance Method Summary collapse

Methods inherited from Fields

#[], #[]=, #bits_on, define_bit_fields_on, define_field, define_field_after, define_field_before, #fields, fields, inherited, #inspect, #offset_of, #optional?, #optional_fields, #present?, remove_bit_fields_on, remove_field, #sz, #to_h, #to_s, update_field

Constructor Details

#initialize(options = {}) ⇒ AbstractTLV

This method is abstract.

Should only be called on real TLV classes, created by create.

Returns a new instance of AbstractTLV.

Parameters:

  • options (Hash) (defaults to: {})

Options Hash (options):

  • :type (Integer)
  • :length (Integer)
  • :value (Object)

Since:



119
120
121
122
123
124
125
126
127
# File 'lib/packetgen/types/abstract_tlv.rb', line 119

def initialize(options={})
  self.class.aliases.each do |al, orig|
    options[orig] = options[al] if options.key?(al)
  end

  super
  # used #value= defined below, which set length if needed
  self.value = options[:value] if options[:value]
end

Class Attribute Details

.aliasesHash

Returns:

  • (Hash)

Since:



63
64
65
# File 'lib/packetgen/types/abstract_tlv.rb', line 63

def aliases
  @aliases
end

Instance Attribute Details

#lengthInteger

This method is abstract.

Length attribute for real TLV class

Returns:

  • (Integer)


# File 'lib/packetgen/types/abstract_tlv.rb', line 95


#typeInteger

This method is abstract.

Type attribute for real TLV class

Returns:

  • (Integer)


# File 'lib/packetgen/types/abstract_tlv.rb', line 95


#valueObject

This method is abstract.

Value attribute for real TLV class

Returns:

  • (Object)


# File 'lib/packetgen/types/abstract_tlv.rb', line 95


Class Method Details

.create(type_class: Int8Enum, length_class: Int8, value_class: String, aliases: {}) ⇒ Class

Generate a TLV class

Parameters:

  • type_class (Class) (defaults to: Int8Enum)

    Class to use for type

  • length_class (Class) (defaults to: Int8)

    Class to use for length

  • value_class (Class) (defaults to: String)

    Class to use for value

Returns:

  • (Class)

Raises:

Since:



72
73
74
75
76
77
78
79
80
81
82
83
84
85
86
87
88
89
90
91
92
93
94
# File 'lib/packetgen/types/abstract_tlv.rb', line 72

def self.create(type_class: Int8Enum, length_class: Int8, value_class: String, aliases: {})
  raise Error, '.create cannot be called on a subclass of PacketGen::Types::AbstractTLV' unless self.equal? AbstractTLV

  klass = Class.new(self)
  klass.aliases = aliases

  if type_class < Enum
    klass.define_field :type, type_class, enum: {}
  else
    klass.define_field :type, type_class
  end
  klass.define_field :length, length_class
  klass.define_field :value, value_class

  aliases.each do |al, orig|
    klass.instance_eval do
      alias_method al, orig if klass.method_defined?(orig)
      alias_method :"#{al}=", :"#{orig}=" if klass.method_defined?(:"#{orig}=")
    end
  end

  klass
end

.define_type_enum(hsh) ⇒ void

This method is abstract.

Should only be called on real TLV classes, created by create.

This method returns an undefined value.

Set enum hash for #type field.

Parameters:

  • hsh (Hash)

    enum hash

Since:



109
110
111
112
# File 'lib/packetgen/types/abstract_tlv.rb', line 109

def self.define_type_enum(hsh)
  field_defs[:type][:enum].clear
  field_defs[:type][:enum].merge!(hsh)
end

Instance Method Details

#human_typeString

This method is abstract.

Should only be called on real TLV class instances.

Get human-readable type

Returns:

Since:



156
157
158
# File 'lib/packetgen/types/abstract_tlv.rb', line 156

def human_type
  self[:type].to_human.to_s
end

#read(str) ⇒ Fields

This method is abstract.

Should only be called on real TLV class instances.

Populate object from a binary string

Parameters:

Returns:

Since:



133
134
135
136
137
138
139
140
141
# File 'lib/packetgen/types/abstract_tlv.rb', line 133

def read(str)
  idx = 0
  self[:type].read str[idx, self[:type].sz]
  idx += self[:type].sz
  self[:length].read str[idx, self[:length].sz]
  idx += self[:length].sz
  self[:value].read str[idx, self.length]
  self
end

#to_humanString

This method is abstract.

Should only be called on real TLV class instances.

Returns:

Since:



162
163
164
165
# File 'lib/packetgen/types/abstract_tlv.rb', line 162

def to_human
  my_value = self[:value].is_a?(String) ? value.inspect : value.to_human
  "type:%s,length:%u,value:#{my_value}" % [human_type, length]
end