From 6799214941d68e4ec2eaa7a578a6dfd0c1ef4018 Mon Sep 17 00:00:00 2001 From: DanB Date: Thu, 20 Sep 2018 14:08:32 +0200 Subject: [PATCH] Diameter method diamAVPAsIface converting go diameter avp value into interface understood internally --- agents/dmtagent.go | 3 +- agents/libdmt.go | 97 ++++++++++++++++++++++++++++++++++++++++++++++ agents/librad.go | 2 +- utils/reflect.go | 11 ++++++ 4 files changed, 111 insertions(+), 2 deletions(-) diff --git a/agents/dmtagent.go b/agents/dmtagent.go index d652b04e7..ba0643637 100644 --- a/agents/dmtagent.go +++ b/agents/dmtagent.go @@ -80,5 +80,6 @@ func (self *DiameterAgent) handlers() diam.Handler { // handleALL is the handler of all messages coming in via Diameter func (self *DiameterAgent) handleALL(c diam.Conn, m *diam.Message) { - utils.Logger.Warning(fmt.Sprintf("<%s> received unexpected message from %s:\n%s", utils.DiameterAgent, c.RemoteAddr(), m)) + utils.Logger.Warning(fmt.Sprintf("<%s> received unexpected message from %s:\n%s", + utils.DiameterAgent, c.RemoteAddr(), m)) } diff --git a/agents/libdmt.go b/agents/libdmt.go index 256695ecd..60a50786d 100644 --- a/agents/libdmt.go +++ b/agents/libdmt.go @@ -19,12 +19,18 @@ along with this program. If not, see package agents import ( + "errors" "fmt" + "net" "os" "path/filepath" "strings" + "time" + "github.com/cgrates/cgrates/config" "github.com/cgrates/cgrates/utils" + "github.com/fiorix/go-diameter/diam" + "github.com/fiorix/go-diameter/diam/datatype" "github.com/fiorix/go-diameter/diam/dict" ) @@ -58,3 +64,94 @@ func loadDictionaries(dictsDir, componentId string) error { return nil }) } + +// diamAVPValue will extract the go primary value out of diameter type value +func diamAVPAsIface(dAVP *diam.AVP) (val interface{}, err error) { + if dAVP == nil { + return nil, errors.New("nil AVP") + } + switch dAVP.Data.Type() { + default: + return nil, fmt.Errorf("unsupported AVP data type: %d", dAVP.Data.Type()) + case datatype.AddressType: + return net.IP([]byte(dAVP.Data.(datatype.Address))), nil + case datatype.DiameterIdentityType: + return string(dAVP.Data.(datatype.DiameterIdentity)), nil + case datatype.DiameterURIType: + return string(dAVP.Data.(datatype.DiameterURI)), nil + case datatype.EnumeratedType: + return int32(dAVP.Data.(datatype.Enumerated)), nil + case datatype.Float32Type: + return float32(dAVP.Data.(datatype.Float32)), nil + case datatype.Float64Type: + return float64(dAVP.Data.(datatype.Float64)), nil + case datatype.IPFilterRuleType: + return string(dAVP.Data.(datatype.IPFilterRule)), nil + case datatype.IPv4Type: + return net.IP([]byte(dAVP.Data.(datatype.IPv4))), nil + case datatype.Integer32Type: + return int32(dAVP.Data.(datatype.Integer32)), nil + case datatype.Integer64Type: + return int64(dAVP.Data.(datatype.Integer64)), nil + case datatype.OctetStringType: + return string(dAVP.Data.(datatype.OctetString)), nil + case datatype.QoSFilterRuleType: + return string(dAVP.Data.(datatype.QoSFilterRule)), nil + case datatype.TimeType: + return time.Time(dAVP.Data.(datatype.Time)), nil + case datatype.UTF8StringType: + return string(dAVP.Data.(datatype.UTF8String)), nil + case datatype.Unsigned32Type: + return uint32(dAVP.Data.(datatype.Unsigned32)), nil + case datatype.Unsigned64Type: + return uint64(dAVP.Data.(datatype.Unsigned64)), nil + } +} + +// newDADataProvider constructs a DataProvider for a diameter message +func newDADataProvider(m *diam.Message) (dP config.DataProvider, err error) { + dP = &diameterDP{m: m, cache: config.NewNavigableMap(nil)} + return +} + +// diameterDP implements engine.DataProvider, serving as diam.Message data decoder +// decoded data is only searched once and cached +type diameterDP struct { + m *diam.Message + cache *config.NavigableMap +} + +// String is part of engine.DataProvider interface +// when called, it will display the already parsed values out of cache +func (dP *diameterDP) String() string { + return utils.ToJSON(dP.cache) +} + +// AsNavigableMap is part of engine.DataProvider interface +func (dP *diameterDP) AsNavigableMap([]*config.FCTemplate) ( + nm *config.NavigableMap, err error) { + return nil, utils.ErrNotImplemented +} + +// FieldAsString is part of engine.DataProvider interface +func (dP *diameterDP) FieldAsString(fldPath []string) (data string, err error) { + var valIface interface{} + valIface, err = dP.FieldAsInterface(fldPath) + if err != nil { + return + } + data, _ = utils.CastFieldIfToString(valIface) + return +} + +// FieldAsInterface is part of engine.DataProvider interface +func (dP *diameterDP) FieldAsInterface(fldPath []string) (data interface{}, err error) { + if data, err = dP.cache.FieldAsInterface(fldPath); err == nil || + err != utils.ErrNotFound { // item found in cache + return + } + err = nil // cancel previous err + + dP.cache.Set(fldPath, data, false) + return +} diff --git a/agents/librad.go b/agents/librad.go index 1dee40fba..a133a22cd 100644 --- a/agents/librad.go +++ b/agents/librad.go @@ -150,7 +150,7 @@ type radiusDP struct { // String is part of engine.DataProvider interface // when called, it will display the already parsed values out of cache func (pk *radiusDP) String() string { - return utils.ToJSON(pk) + return utils.ToJSON(pk.cache) } // FieldAsInterface is part of engine.DataProvider interface diff --git a/utils/reflect.go b/utils/reflect.go index 4d59897d0..8475ad705 100644 --- a/utils/reflect.go +++ b/utils/reflect.go @@ -21,6 +21,7 @@ package utils import ( "errors" "fmt" + "net" "reflect" "strconv" "time" @@ -238,10 +239,18 @@ func IfaceAsString(fld interface{}) (out string, err error) { switch fld.(type) { case int: return strconv.Itoa(fld.(int)), nil + case int32: + return strconv.FormatInt(int64(fld.(int32)), 10), nil case int64: return strconv.FormatInt(fld.(int64), 10), nil + case uint32: + return strconv.FormatUint(uint64(fld.(int32)), 10), nil + case uint64: + return strconv.FormatUint(fld.(uint64), 10), nil case bool: return strconv.FormatBool(fld.(bool)), nil + case float32: + return strconv.FormatFloat(float64(fld.(float32)), 'f', -1, 64), nil case float64: return strconv.FormatFloat(fld.(float64), 'f', -1, 64), nil case []uint8: @@ -254,6 +263,8 @@ func IfaceAsString(fld interface{}) (out string, err error) { return fld.(time.Duration).String(), nil case time.Time: return fld.(time.Time).Format(time.RFC3339), nil + case net.IP: + return fld.(net.IP).String(), nil case string: return fld.(string), nil default: // Maybe we are lucky and the value converts to string