// messageAddAVPsWithPath will dynamically add AVPs into the message // append: append to the message, on false overwrite if AVP is single or add to group if AVP is Grouped func messageSetAVPsWithPath(m *diam.Message, path []interface{}, avpValStr string, appnd bool, timezone string) error { if len(path) == 0 { return errors.New("Empty path as AVP filter") } dictAVPs := make([]*dict.AVP, len(path)) // for each subpath, one dictionary AVP for i, subpath := range path { if dictAVP, err := m.Dictionary().FindAVP(m.Header.ApplicationID, subpath); err != nil { return err } else if dictAVP == nil { return fmt.Errorf("Cannot find AVP with id: %s", path[len(path)-1]) } else { dictAVPs[i] = dictAVP } } if dictAVPs[len(path)-1].Data.Type == diam.GroupedAVPType { return errors.New("Last AVP in path needs not to be GroupedAVP") } var msgAVP *diam.AVP // Keep a reference here towards last AVP lastAVPIdx := len(path) - 1 for i := lastAVPIdx; i >= 0; i-- { var typeVal datatype.Type if i == lastAVPIdx { avpValByte, err := serializeAVPValueFromString(dictAVPs[i], avpValStr, timezone) if err != nil { return err } typeVal, err = datatype.Decode(dictAVPs[i].Data.Type, avpValByte) if err != nil { return err } } else { typeVal = &diam.GroupedAVP{ AVP: []*diam.AVP{msgAVP}} } newMsgAVP := diam.NewAVP(dictAVPs[i].Code, avp.Mbit, dictAVPs[i].VendorID, typeVal) // FixMe: maybe Mbit with dictionary one if i == lastAVPIdx-1 && !appnd { // last AVP needs to be appended in group avps, _ := m.FindAVPsWithPath(path[:lastAVPIdx], dict.UndefinedVendorID) if len(avps) != 0 { // Group AVP already in the message prevGrpData := avps[0].Data.(*diam.GroupedAVP) prevGrpData.AVP = append(prevGrpData.AVP, msgAVP) m.Header.MessageLength += uint32(msgAVP.Len()) return nil } } msgAVP = newMsgAVP } if !appnd { // Not group AVP, replace the previous set one with this one avps, _ := m.FindAVPsWithPath(path, dict.UndefinedVendorID) if len(avps) != 0 { // Group AVP already in the message m.Header.MessageLength -= uint32(avps[0].Len()) // decrease message length since we overwrite *avps[0] = *msgAVP m.Header.MessageLength += uint32(msgAVP.Len()) return nil } } m.AVP = append(m.AVP, msgAVP) m.Header.MessageLength += uint32(msgAVP.Len()) return nil }
// DecodeFromBytes decodes the bytes of a Diameter AVP. // It uses the given application id and dictionary for decoding the bytes. func (a *AVP) DecodeFromBytes(data []byte, application uint32, dictionary *dict.Parser) error { dl := len(data) if dl < 8 { return fmt.Errorf("Not enough data to decode AVP header: %d bytes", dl) } a.Code = binary.BigEndian.Uint32(data[0:4]) a.Flags = data[4] a.Length = int(uint24to32(data[5:8])) if dl < int(a.Length) { return fmt.Errorf("Not enough data to decode AVP: %d != %d", dl, a.Length) } data = data[:a.Length] // this cuts padded bytes off var hdrLength int var payload []byte // Read VendorId when required. if a.Flags&avp.Vbit == avp.Vbit { a.VendorID = binary.BigEndian.Uint32(data[8:12]) payload = data[12:] hdrLength = 12 } else { payload = data[8:] hdrLength = 8 } // Find this code in the dictionary. dictAVP, err := dictionary.FindAVPWithVendor(application, a.Code, a.VendorID) if err != nil { return err } bodyLen := a.Length - hdrLength if n := len(payload); n < bodyLen { return fmt.Errorf( "Not enough data to decode AVP: %d != %d", hdrLength, n, ) } a.Data, err = datatype.Decode(dictAVP.Data.Type, payload) if err != nil { return err } // Handle grouped AVPs. if a.Data.Type() == datatype.GroupedType { a.Data, err = DecodeGrouped( a.Data.(datatype.Grouped), application, dictionary, ) if err != nil { return err } } return nil }