class Diameter::AVP

Represents a Diameter AVP. Use this for non-vendor-specific AVPs, and its subclass VendorSpecificAVP for ones defined for a particular vendor. @!attribute [r] code

@return [Fixnum] The AVP Code

@!attribute [r] mandatory

@return [true, false] Whether this AVP is mandatory (i.e. its M flag is set)

Attributes

code[R]
mandatory[R]
vendor_id[R]

Public Class Methods

create(name, val, options = {}) click to toggle source

Creates an AVP by name, and assigns it a value.

@param name The name of the AVP, e.g. “Origin-Host” @param val The value of the AVP. Must be of the type defined for

that AVP - e.g. a Fixnum for an AVP defined as Unsigned32, a
String for an AVP defined as OctetString, or an IPAddr for an AVP
defined as IPAddress.

@option opts [true, false] mandatory

Whether understanding this AVP is mandatory within this
application.

@return [AVP] The AVP that was created.

# File lib/diameter/avp.rb, line 77
def self.create(name, val, options = {})
  code, type, vendor = AVPNames.get(name)
  options[:vendor_id] = vendor
  avp = AVP.new(code, options)

  set_content(avp, type, val)

  avp
end
define(name, code, type, vendor=nil) click to toggle source

Defines a new AVP that can subsequently be created/retrieved by name.

@param name [String] The AVP name @param code [Fixnum] The AVP Code @param type [AVPType] The type of this AVP's value @param vendor [Fixnum] Optional vendor ID for a vendor-specific

AVP.

@return [void]

# File lib/diameter/avp.rb, line 96
def self.define(name, code, type, vendor=nil)
  AVPNames.add(name, code, type, vendor)
end
new(code, options = {}) click to toggle source

@api private

Prefer {AVP.create} where possible.

# File lib/diameter/avp.rb, line 58
def initialize(code, options = {})
  @code = code
  @vendor_id = options[:vendor_id] || 0
  @content = options[:content] || ''
  @mandatory = options.fetch(:mandatory, true)
end

Private Class Methods

set_content(avp, type, val) click to toggle source

@!endgroup

# File lib/diameter/avp.rb, line 355
def self.set_content(avp, type, val)
  case type
  when Grouped
    avp.grouped_value = val
  when OctetString
    avp.octet_string = val
  when Unsigned32
    avp.uint32 = val
  when Unsigned64
    avp.uint64 = val
  when Integer32
    avp.int32 = val
  when Integer64
    avp.int64 = val
  when Float32
    avp.float32 = val
  when Float64
    avp.float64 = val
  when IPAddress
    avp.ip_address = val
  end
end

Public Instance Methods

[](name)
Alias for: inner_avp
float32() click to toggle source

Returns this AVP's byte data, interpreted as a Float32.

@return [Float] The contained Float32.

# File lib/diameter/avp.rb, line 300
def float32
  @content.unpack('g')[0]
end
float32=(value) click to toggle source

Sets this AVP's byte data to a Float32.

@param [Float] value @return [void]

# File lib/diameter/avp.rb, line 308
def float32=(value)
  @content = [value].pack('g')
end
float64() click to toggle source

Returns this AVP's byte data, interpreted as a Float64.

@return [Float] The contained Float64.

# File lib/diameter/avp.rb, line 315
def float64
  @content.unpack('G')[0]
end
float64=(value) click to toggle source

Sets this AVP's byte data to a Float64.

@param [Float] value @return [void]

# File lib/diameter/avp.rb, line 323
def float64=(value)
  @content = [value].pack('G')
end
grouped_value() click to toggle source

Returns this AVP's byte data, interpreted as a {tools.ietf.org/html/rfc6733#section-4.4 Grouped AVP}.

@return [Array<AVP>] The contained AVPs.

# File lib/diameter/avp.rb, line 169
def grouped_value
  AVPParser.parse_avps_int(@content)
end
grouped_value=(avps) click to toggle source

Sets this AVP's byte data to a {tools.ietf.org/html/rfc6733#section-4.4 Grouped AVP}.

@param [Array<AVP>] avps The AVPs that should be contained within

this AVP.

@return [void]

# File lib/diameter/avp.rb, line 179
def grouped_value=(avps)
  new_content = ''
  avps.each { |a| new_content += a.to_wire }
  @content = new_content
end
inner_avp(name) click to toggle source

For a grouped AVP, returns the first AVP with this name it contains.

@param [String] name The AVP name @return [AVP] if this AVP is found inside the Grouped AVP @return [nil] if this AVP is not found inside the Grouped AVP

# File lib/diameter/avp.rb, line 191
def inner_avp(name)
  avps = inner_avps(name)

  if avps.empty?
    nil
  else
    avps[0]
  end
end
Also aliased as: []
inner_avps(name) click to toggle source

For a grouped AVP, returns all AVPs it contains with this name.

@param [String] name The AVP name @return [Array<AVP>]

# File lib/diameter/avp.rb, line 205
def inner_avps(name)
  code, _type, _vendor = AVPNames.get(name)

  grouped_value.select { |a| a.code == code }
end
int32() click to toggle source

Returns this AVP's byte data, interpreted as an Integer32.

@return [Fixnum] The contained Integer32.

# File lib/diameter/avp.rb, line 240
def int32
  @content.unpack('l>')[0]
end
int32=(value) click to toggle source

Sets this AVP's byte data to an Integer32.

@param [Fixnum] value @return [void]

# File lib/diameter/avp.rb, line 248
def int32=(value)
  @content = [value].pack('l>')
end
int64() click to toggle source

Returns this AVP's byte data, interpreted as an Integer64.

@return [Fixnum] The contained Integer64.

# File lib/diameter/avp.rb, line 255
def int64
  @content.unpack('q>')[0]
end
int64=(value) click to toggle source

Sets this AVP's byte data to an Integer64.

@param [Fixnum] value @return [void]

# File lib/diameter/avp.rb, line 263
def int64=(value)
  @content = [value].pack('q>')
end
ip_address() click to toggle source

Returns this AVP's byte data, interpreted as an {tools.ietf.org/html/rfc6733#section-4.3.1 Address}.

@return [IPAddr] The contained

{http://tools.ietf.org/html/rfc6733#section-4.3.1 Address}.
# File lib/diameter/avp.rb, line 332
def ip_address
  IPAddr.new_ntoh(@content[2..-1])
end
ip_address=(value) click to toggle source

Sets this AVP's byte data to an Address.

@param [IPAddr] value @return [void]

# File lib/diameter/avp.rb, line 340
def ip_address=(value)
  bytes = if value.ipv4?
            [1].pack('n')
          else
            [2].pack('n')
          end

  bytes += value.hton
  @content = bytes
end
octet_string() click to toggle source

Returns this AVP's byte data, interpreted as an OctetString.

@return [String] The contained OctetString.

# File lib/diameter/avp.rb, line 223
def octet_string
  @content
end
octet_string=(value) click to toggle source

Sets this AVP's byte data to an OctetString.

@param [String] value The octets to use as the value. @return [void]

# File lib/diameter/avp.rb, line 231
def octet_string=(value)
  @content = value
end
to_s() click to toggle source

Returns a string representation of this AVP. Makes a best-effort attempt to guess the type of the content (even for unknown AVPs) and display it sensibly.

@example

avp.to_s => "AVP 267, mandatory: true, content as int32: 1"
# File lib/diameter/avp.rb, line 128
def to_s
  has_all_ascii_values =
    @content.bytes.reject { |c| (32 < c && c < 126) }.empty?

  could_be_32bit_num = (@content.length == 4)
  could_be_64bit_num = (@content.length == 8)

  could_be_ip = ((@content.length == 6 && @content[0..1] == "\x00\x01") ||
                 (@content.length == 18 && @content[0..1] == "\x00\x02"))

  maybe_grouped = !(has_all_ascii_values ||
                    could_be_64bit_num   ||
                    could_be_32bit_num   ||
                    could_be_ip)

  s = vendor_specific? ? "AVP #{@code}, Vendor-ID #{@vendor_id}, mandatory: #{@mandatory}" :
          "AVP #{@code}, mandatory: #{@mandatory}"
  s += ", content as string: #{@content}" if has_all_ascii_values
  s += ", content as int32: #{uint32}" if could_be_32bit_num
  s += ", content as int64: #{uint64}" if could_be_64bit_num
  s += ", content as ip: #{ip_address}" if could_be_ip
  s += ", grouped AVP, #{grouped_value.collect(&:to_s)}" if maybe_grouped

  s
end
to_wire() click to toggle source

Returns this AVP encoded properly as bytes in network byte order, suitable for sending over a TCP or SCTP connection. See {tools.ietf.org/html/rfc6733#section-4.1} for the format.

@return [String] The bytes representing this AVP

# File lib/diameter/avp.rb, line 106
def to_wire
  if vendor_specific?
    to_wire_vendor
  else
    to_wire_novendor
  end
end
uint32() click to toggle source

Returns this AVP's byte data, interpreted as an Unsigned32.

@return [Fixnum] The contained Unsigned32.

# File lib/diameter/avp.rb, line 270
def uint32
  @content.unpack('N')[0]
end
uint32=(value) click to toggle source

Sets this AVP's byte data to an Unsigned32.

@param [Fixnum] value @return [void]

# File lib/diameter/avp.rb, line 278
def uint32=(value)
  @content = [value].pack('N')
end
uint64() click to toggle source

Returns this AVP's byte data, interpreted as an Unsigned64.

@return [Fixnum] The contained Unsigned64.

# File lib/diameter/avp.rb, line 285
def uint64
  @content.unpack('Q>')[0]
end
uint64=(value) click to toggle source

Sets this AVP's byte data to an Unsigned64.

@param [Fixnum] value @return [void]

# File lib/diameter/avp.rb, line 293
def uint64=(value)
  @content = [value].pack('Q>')
end
vendor_specific?() click to toggle source

@!attribute [r] vendor_specific?

@return [true, false] Whether this AVP is mandatory
(i.e. its M flag is set)
# File lib/diameter/avp.rb, line 159
def vendor_specific?
  @vendor_id != 0
end

Protected Instance Methods

padded_content() click to toggle source
# File lib/diameter/avp.rb, line 394
def padded_content
  wire_content = @content
  wire_content += "\x00" while ((wire_content.length % 4) != 0)
  wire_content
end

Private Instance Methods

to_wire_novendor() click to toggle source
# File lib/diameter/avp.rb, line 378
def to_wire_novendor
  length_8, length_16 = UInt24.to_u8_and_u16(@content.length + 8)
  avp_flags = @mandatory ? '01000000' : '00000000'
  header = [@code, avp_flags, length_8, length_16].pack('NB8Cn')
  header + padded_content
end
to_wire_vendor() click to toggle source
# File lib/diameter/avp.rb, line 385
def to_wire_vendor
  length_8, length_16 = UInt24.to_u8_and_u16(@content.length + 12)
  avp_flags = @mandatory ? '11000000' : '10000000'
  header = [@code, avp_flags, length_8, length_16, @vendor_id].pack('NB8CnN')
  header + padded_content
end